|
|
1.1 ! root 1: /* Perform instruction reorganizations for delay slot filling. ! 2: Copyright (C) 1992 Free Software Foundation, Inc. ! 3: Contributed by Richard Kenner ([email protected]). ! 4: Hacked by Michael Tiemann ([email protected]). ! 5: ! 6: This file is part of GNU CC. ! 7: ! 8: GNU CC is free software; you can redistribute it and/or modify ! 9: it under the terms of the GNU General Public License as published by ! 10: the Free Software Foundation; either version 2, or (at your option) ! 11: any later version. ! 12: ! 13: GNU CC is distributed in the hope that it will be useful, ! 14: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 15: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 16: GNU General Public License for more details. ! 17: ! 18: You should have received a copy of the GNU General Public License ! 19: along with GNU CC; see the file COPYING. If not, write to ! 20: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 21: ! 22: ! 23: #include "insn-attr.h" ! 24: ! 25: #ifdef DELAY_SLOTS ! 26: ! 27: /* Instruction reorganization pass. ! 28: ! 29: This pass runs after register allocation and final jump ! 30: optimization. It should be the last pass to run before peephole. ! 31: It serves primarily to fill delay slots of insns, typically branch ! 32: and call insns. Other insns typically involve more complicated ! 33: interractions of data dependencies and resource constraints, and ! 34: are better handled by scheduling before register allocation (by the ! 35: function `schedule_insns'). ! 36: ! 37: The Branch Penalty is the number of extra cycles that are needed to ! 38: execute a branch insn. On an ideal machine, branches take a single ! 39: cycle, and the Branch Penalty is 0. Several RISC machines approach ! 40: branch delays differently: ! 41: ! 42: The MIPS and AMD 29000 have a single branch delay slot. Most insns ! 43: (except other branches) can be used to fill this slot. When the ! 44: slot is filled, two insns execute in two cycles, reducing the ! 45: branch penalty to zero. ! 46: ! 47: The Motorola 88000 conditionally exposes its branch delay slot, ! 48: so code is shorter when it is turned off, but will run faster ! 49: when useful insns are scheduled there. ! 50: ! 51: The IBM ROMP has two forms of branch and call insns, both with and ! 52: without a delay slot. Much like the 88k, insns not using the delay ! 53: slot can be shorted (2 bytes vs. 4 bytes), but will run slowed. ! 54: ! 55: The SPARC always has a branch delay slot, but its effects can be ! 56: annulled when the branch is not taken. This means that failing to ! 57: find other sources of insns, we can hoist an insn from the branch ! 58: target that would only be safe to execute knowing that the branch ! 59: is taken. ! 60: ! 61: Three techniques for filling delay slots have been implemented so far: ! 62: ! 63: (1) `fill_simple_delay_slots' is the simplest, most efficient way ! 64: to fill delay slots. This pass first looks for insns which come ! 65: from before the branch and which are safe to execute after the ! 66: branch. Then it searches after the insn requiring delay slots or, ! 67: in the case of a branch, for insns that are after the point at ! 68: which the branch merges into the fallthrough code, if such a point ! 69: exists. When such insns are found, the branch penalty decreases ! 70: and no code expansion takes place. ! 71: ! 72: (2) `fill_eager_delay_slots' is more complicated: it is used for ! 73: scheduling conditional jumps, or for scheduling jumps which cannot ! 74: be filled using (1). A machine need not have annulled jumps to use ! 75: this strategy, but it helps (by keeping more options open). ! 76: `fill_eager_delay_slots' tries to guess the direction the branch ! 77: will go; if it guesses right 100% of the time, it can reduce the ! 78: branch penalty as much as `fill_eager_delay_slots' does. If it ! 79: guesses wrong 100% of the time, it might as well schedule nops (or ! 80: on the m88k, unexpose the branch slot). When ! 81: `fill_eager_delay_slots' takes insns from the fall-through path of ! 82: the jump, usually there is no code expansion; when it takes insns ! 83: from the branch target, there is code expansion if it is not the ! 84: only way to reach that target. ! 85: ! 86: (3) `relax_delay_slots' uses a set of rules to simplify code that ! 87: has been reorganized by (1) and (2). It finds cases where ! 88: conditional test can be eliminated, jumps can be threaded, extra ! 89: insns can be eliminated, etc. It is the job of (1) and (2) to do a ! 90: good job of scheduling locally; `relax_delay_slots' takes care of ! 91: making the various individual schedules work well together. It is ! 92: especially tuned to handle the control flow interactions of branch ! 93: insns. It does nothing for insns with delay slots that do not ! 94: branch. ! 95: ! 96: On machines that use CC0, we are very conservative. We will not make ! 97: a copy of an insn involving CC0 since we want to maintain a 1-1 ! 98: correspondance between the insn that sets and uses CC0. The insns are ! 99: allowed to be separated by placing an insn that sets CC0 (but not an insn ! 100: that uses CC0; we could do this, but it doesn't seem worthwhile) in a ! 101: delay slot. In that case, we point each insn at the other with REG_CC_USER ! 102: and REG_CC_SETTER notes. Note that these restrictions affect very few ! 103: machines because most RISC machines with delay slots will not use CC0 ! 104: (the RT is the only known exception at this point). ! 105: ! 106: Not yet implemented: ! 107: ! 108: The Acorn Risc Machine can conditionally execute most insns, so ! 109: it is profitable to move single insns into a position to execute ! 110: based on the condition code of the previous insn. ! 111: ! 112: The HP-PA can conditionally nullify insns, providing a similar ! 113: effect to the ARM, differing mostly in which insn is "in charge". */ ! 114: ! 115: #include <stdio.h> ! 116: #include "config.h" ! 117: #include "rtl.h" ! 118: #include "insn-config.h" ! 119: #include "conditions.h" ! 120: #include "hard-reg-set.h" ! 121: #include "basic-block.h" ! 122: #include "regs.h" ! 123: #include "insn-flags.h" ! 124: #include "recog.h" ! 125: #include "flags.h" ! 126: #include "output.h" ! 127: #include "obstack.h" ! 128: ! 129: #define obstack_chunk_alloc xmalloc ! 130: #define obstack_chunk_free free ! 131: ! 132: extern int xmalloc (); ! 133: extern void free (); ! 134: ! 135: #ifndef ANNUL_IFTRUE_SLOTS ! 136: #define eligible_for_annul_true(INSN, SLOTS, TRIAL) 0 ! 137: #endif ! 138: #ifndef ANNUL_IFFALSE_SLOTS ! 139: #define eligible_for_annul_false(INSN, SLOTS, TRIAL) 0 ! 140: #endif ! 141: ! 142: /* Insns which have delay slots that have not yet been filled. */ ! 143: ! 144: static struct obstack unfilled_slots_obstack; ! 145: static rtx *unfilled_firstobj; ! 146: ! 147: /* Define macros to refer to the first and last slot containing unfilled ! 148: insns. These are used because the list may move and its address ! 149: should be recomputed at each use. */ ! 150: ! 151: #define unfilled_slots_base \ ! 152: ((rtx *) obstack_base (&unfilled_slots_obstack)) ! 153: ! 154: #define unfilled_slots_next \ ! 155: ((rtx *) obstack_next_free (&unfilled_slots_obstack)) ! 156: ! 157: /* This structure is used to indicate which hardware resources are set or ! 158: needed by insns so far. */ ! 159: ! 160: struct resources ! 161: { ! 162: char memory; /* Insn sets or needs a memory location. */ ! 163: char volatil; /* Insn sets or needs a volatile memory loc. */ ! 164: char cc; /* Insn sets or needs the condition codes. */ ! 165: HARD_REG_SET regs; /* Which registers are set or needed. */ ! 166: }; ! 167: ! 168: /* Macro to clear all resources. */ ! 169: #define CLEAR_RESOURCE(RES) \ ! 170: do { (RES)->memory = (RES)->volatil = (RES)->cc = 0; \ ! 171: CLEAR_HARD_REG_SET ((RES)->regs); } while (0) ! 172: ! 173: /* Indicates what resources are required at function end. */ ! 174: static struct resources end_of_function_needs; ! 175: ! 176: /* Points to the label before the end of the function. */ ! 177: static rtx end_of_function_label; ! 178: ! 179: /* This structure is used to record livness information at the targets or ! 180: fallthrough insns of branches. We will most likely need the information ! 181: at targets again, so save them in a hash table rather than recomputing them ! 182: each time. */ ! 183: ! 184: struct target_info ! 185: { ! 186: int uid; /* INSN_UID of target. */ ! 187: struct target_info *next; /* Next info for same hash bucket. */ ! 188: HARD_REG_SET live_regs; /* Registers live at target. */ ! 189: int block; /* Basic block number containing target. */ ! 190: int bb_tick; /* Generation count of basic block info. */ ! 191: }; ! 192: ! 193: #define TARGET_HASH_PRIME 257 ! 194: ! 195: /* Define the hash table itself. */ ! 196: static struct target_info **target_hash_table; ! 197: ! 198: /* For each basic block, we maintain a generation number of its basic ! 199: block info, which is updated each time we move an insn from the ! 200: target of a jump. This is the generation number indexed by block ! 201: number. */ ! 202: ! 203: static int *bb_ticks; ! 204: ! 205: /* Mapping between INSN_UID's and position in the code since INSN_UID's do ! 206: not always monotonically increase. */ ! 207: static int *uid_to_ruid; ! 208: ! 209: /* Highest valid index in `uid_to_ruid'. */ ! 210: static int max_uid; ! 211: ! 212: /* Forward references: */ ! 213: ! 214: static int redundant_insn_p (); ! 215: static void update_block (); ! 216: ! 217: /* Given X, some rtl, and RES, a pointer to a `struct resource', mark ! 218: which resources are references by the insn. If INCLUDE_CALLED_ROUTINE ! 219: is TRUE, resources used by the called routine will be included for ! 220: CALL_INSNs. */ ! 221: ! 222: static void ! 223: mark_referenced_resources (x, res, include_called_routine) ! 224: register rtx x; ! 225: register struct resources *res; ! 226: register int include_called_routine; ! 227: { ! 228: register enum rtx_code code = GET_CODE (x); ! 229: register int i, j; ! 230: register char *format_ptr; ! 231: ! 232: /* Handle leaf items for which we set resource flags. Also, special-case ! 233: CALL, SET and CLOBBER operators. */ ! 234: switch (code) ! 235: { ! 236: case CONST: ! 237: case CONST_INT: ! 238: case CONST_DOUBLE: ! 239: case PC: ! 240: case SYMBOL_REF: ! 241: case LABEL_REF: ! 242: return; ! 243: ! 244: case SUBREG: ! 245: if (GET_CODE (SUBREG_REG (x)) != REG) ! 246: mark_referenced_resources (SUBREG_REG (x), res, 0); ! 247: else ! 248: { ! 249: int regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x); ! 250: int last_regno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x)); ! 251: for (i = regno; i < last_regno; i++) ! 252: SET_HARD_REG_BIT (res->regs, i); ! 253: } ! 254: return; ! 255: ! 256: case REG: ! 257: for (i = 0; i < HARD_REGNO_NREGS (REGNO (x), GET_MODE (x)); i++) ! 258: SET_HARD_REG_BIT (res->regs, REGNO (x) + i); ! 259: return; ! 260: ! 261: case MEM: ! 262: /* If this memory shouldn't change, it really isn't referencing ! 263: memory. */ ! 264: if (! RTX_UNCHANGING_P (x)) ! 265: res->memory = 1; ! 266: res->volatil = MEM_VOLATILE_P (x); ! 267: ! 268: /* Mark registers used to access memory. */ ! 269: mark_referenced_resources (XEXP (x, 0), res, 0); ! 270: return; ! 271: ! 272: case CC0: ! 273: res->cc = 1; ! 274: return; ! 275: ! 276: case UNSPEC_VOLATILE: ! 277: case ASM_INPUT: ! 278: /* Traditional asm's are always volatile. */ ! 279: res->volatil = 1; ! 280: return; ! 281: ! 282: case ASM_OPERANDS: ! 283: res->volatil = MEM_VOLATILE_P (x); ! 284: ! 285: /* For all ASM_OPERANDS, we must traverse the vector of input operands. ! 286: We can not just fall through here since then we would be confused ! 287: by the ASM_INPUT rtx inside ASM_OPERANDS, which do not indicate ! 288: traditional asms unlike their normal usage. */ ! 289: ! 290: for (i = 0; i < ASM_OPERANDS_INPUT_LENGTH (x); i++) ! 291: mark_referenced_resources (ASM_OPERANDS_INPUT (x, i), res, 0); ! 292: return; ! 293: ! 294: case CALL: ! 295: /* The first operand will be a (MEM (xxx)) but doesn't really reference ! 296: memory. The second operand may be referenced, though. */ ! 297: mark_referenced_resources (XEXP (XEXP (x, 0), 0), res, 0); ! 298: mark_referenced_resources (XEXP (x, 1), res, 0); ! 299: return; ! 300: ! 301: case SET: ! 302: /* Usually, the first operand of SET is set, not referenced. But ! 303: registers used to access memory are referenced. SET_DEST is ! 304: also referenced if it is a ZERO_EXTRACT or SIGN_EXTRACT. */ ! 305: ! 306: mark_referenced_resources (SET_SRC (x), res, 0); ! 307: ! 308: x = SET_DEST (x); ! 309: if (GET_CODE (x) == SIGN_EXTRACT || GET_CODE (x) == ZERO_EXTRACT) ! 310: mark_referenced_resources (x, res, 0); ! 311: else if (GET_CODE (x) == SUBREG) ! 312: x = SUBREG_REG (x); ! 313: if (GET_CODE (x) == MEM) ! 314: mark_referenced_resources (XEXP (x, 0), res, 0); ! 315: return; ! 316: ! 317: case CLOBBER: ! 318: return; ! 319: ! 320: case CALL_INSN: ! 321: if (include_called_routine) ! 322: { ! 323: /* A CALL references memory, the frame pointer if it exists, the ! 324: stack pointer, any global registers and any registers given in ! 325: USE insns immediately in front of the CALL. ! 326: ! 327: However, we may have moved some of the parameter loading insns ! 328: into the delay slot of this CALL. If so, the USE's for them ! 329: don't count and should be skipped. */ ! 330: rtx insn = PREV_INSN (x); ! 331: rtx sequence = 0; ! 332: int seq_size = 0; ! 333: int i; ! 334: ! 335: /* If we are part of a delay slot sequence, point at the SEQUENCE. */ ! 336: if (NEXT_INSN (insn) != x) ! 337: { ! 338: sequence = PATTERN (NEXT_INSN (insn)); ! 339: seq_size = XVECLEN (sequence, 0); ! 340: if (GET_CODE (sequence) != SEQUENCE) ! 341: abort (); ! 342: } ! 343: ! 344: res->memory = 1; ! 345: SET_HARD_REG_BIT (res->regs, STACK_POINTER_REGNUM); ! 346: if (frame_pointer_needed) ! 347: SET_HARD_REG_BIT (res->regs, FRAME_POINTER_REGNUM); ! 348: ! 349: for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) ! 350: if (global_regs[i]) ! 351: SET_HARD_REG_BIT (res->regs, i); ! 352: ! 353: /* Skip any labels between the CALL_INSN and possible USE insns. */ ! 354: while (GET_CODE (insn) == CODE_LABEL) ! 355: insn = PREV_INSN (insn); ! 356: ! 357: for ( ; (insn && GET_CODE (insn) == INSN ! 358: && GET_CODE (PATTERN (insn)) == USE); ! 359: insn = PREV_INSN (insn)) ! 360: { ! 361: for (i = 1; i < seq_size; i++) ! 362: { ! 363: rtx slot_pat = PATTERN (XVECEXP (sequence, 0, i)); ! 364: if (GET_CODE (slot_pat) == SET ! 365: && rtx_equal_p (SET_DEST (slot_pat), ! 366: XEXP (PATTERN (insn), 0))) ! 367: break; ! 368: } ! 369: if (i >= seq_size) ! 370: mark_referenced_resources (XEXP (PATTERN (insn), 0), res, 0); ! 371: } ! 372: } ! 373: ! 374: /* ... fall through to other INSN procesing ... */ ! 375: ! 376: case INSN: ! 377: case JUMP_INSN: ! 378: /* No special processing, just speed up. */ ! 379: mark_referenced_resources (PATTERN (x), res, include_called_routine); ! 380: return; ! 381: } ! 382: ! 383: /* Process each sub-expression and flag what it needs. */ ! 384: format_ptr = GET_RTX_FORMAT (code); ! 385: for (i = 0; i < GET_RTX_LENGTH (code); i++) ! 386: switch (*format_ptr++) ! 387: { ! 388: case 'e': ! 389: mark_referenced_resources (XEXP (x, i), res, include_called_routine); ! 390: break; ! 391: ! 392: case 'E': ! 393: for (j = 0; j < XVECLEN (x, i); j++) ! 394: mark_referenced_resources (XVECEXP (x, i, j), res, ! 395: include_called_routine); ! 396: break; ! 397: } ! 398: } ! 399: ! 400: /* Given an insn, INSN, and a pointer to a `struct resource', RES, indicate ! 401: which resources are modified by the insn. If INCLUDE_CALLED_ROUTINE ! 402: is TRUE, also mark resources potentially set by the called routine. ! 403: ! 404: We never mark the insn as modifying the condition code unless it explicitly ! 405: SETs CC0 even though this is not totally correct. The reason for this is ! 406: that we require a SET of CC0 to immediately preceed the reference to CC0. ! 407: So if some other insn sets CC0 as a side-effect, we know it cannot affect ! 408: our computation and thus may be placed in a delay slot. */ ! 409: ! 410: static void ! 411: mark_set_resources (insn, res, include_called_routine) ! 412: register rtx insn; ! 413: register struct resources *res; ! 414: int include_called_routine; ! 415: { ! 416: register int i; ! 417: ! 418: switch (GET_CODE (insn)) ! 419: { ! 420: case NOTE: ! 421: case BARRIER: ! 422: case CODE_LABEL: ! 423: /* These don't set any resources. */ ! 424: return; ! 425: ! 426: case CALL_INSN: ! 427: /* Called routine modifies the condition code, memory, any registers ! 428: that aren't saved across calls, global registers and anything ! 429: explicitly CLOBBERed immediately after the CALL_INSN. */ ! 430: ! 431: if (include_called_routine) ! 432: { ! 433: rtx next = NEXT_INSN (insn); ! 434: ! 435: res->cc = res->memory = 1; ! 436: for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) ! 437: if (call_used_regs[i] || global_regs[i]) ! 438: SET_HARD_REG_BIT (res->regs, i); ! 439: ! 440: /* Skip any possible labels between the CALL_INSN and CLOBBERs. */ ! 441: while (GET_CODE (next) == CODE_LABEL) ! 442: next = NEXT_INSN (next); ! 443: ! 444: for (; (next && GET_CODE (next) == INSN ! 445: && GET_CODE (PATTERN (next)) == CLOBBER); ! 446: next = NEXT_INSN (next)) ! 447: mark_referenced_resources (XEXP (PATTERN (next), 0), res, 0); ! 448: } ! 449: ! 450: /* ... and also what it's RTL says it modifies, if anything. */ ! 451: ! 452: case JUMP_INSN: ! 453: case INSN: ! 454: { ! 455: register rtx body = PATTERN (insn); ! 456: register rtx note; ! 457: ! 458: /* An insn consisting of just a CLOBBER (or USE) is ! 459: just for flow and doesn't actually do anything, so we don't check ! 460: for it. ! 461: ! 462: If the source of a SET is a CALL, this is actually done by ! 463: the called routine. So only include it if we are to include the ! 464: effects of the calling routine. */ ! 465: ! 466: if (GET_CODE (body) == SET ! 467: && (include_called_routine || GET_CODE (SET_SRC (body)) != CALL)) ! 468: mark_referenced_resources (SET_DEST (body), res, 0); ! 469: else if (GET_CODE (body) == PARALLEL) ! 470: { ! 471: for (i = 0; i < XVECLEN (body, 0); i++) ! 472: if ((GET_CODE (XVECEXP (body, 0, i)) == SET ! 473: && (include_called_routine ! 474: || GET_CODE (SET_SRC (XVECEXP (body, 0, i))) != CALL)) ! 475: || GET_CODE (XVECEXP (body, 0, i)) == CLOBBER) ! 476: mark_referenced_resources (SET_DEST (XVECEXP (body, 0, i)), ! 477: res, 0); ! 478: } ! 479: else if (GET_CODE (body) == SEQUENCE) ! 480: for (i = 0; i < XVECLEN (body, 0); i++) ! 481: if (! (INSN_ANNULLED_BRANCH_P (XVECEXP (body, 0, 0)) ! 482: && INSN_FROM_TARGET_P (XVECEXP (body, 0, i)))) ! 483: mark_set_resources (XVECEXP (body, 0, i), res, ! 484: include_called_routine); ! 485: ! 486: #ifdef AUTO_INC_DEC ! 487: /* If any register are incremented or decremented in an address, ! 488: they are set here. */ ! 489: for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) ! 490: if (REG_NOTE_KIND (note) == REG_INC) ! 491: mark_referenced_resources (XEXP (note, 0), res, 0); ! 492: #endif ! 493: ! 494: #ifdef PUSH_ROUNDING ! 495: /* An insn that has a PRE_DEC on SP will not have a REG_INC note. ! 496: Until we fix this correctly, consider all insns as modifying ! 497: SP on such machines. So far, we don't have delay slot scheduling ! 498: on any machines with PUSH_ROUNDING. */ ! 499: SET_HARD_REG_BIT (res->regs, STACK_POINTER_REGNUM); ! 500: #endif ! 501: return; ! 502: } ! 503: ! 504: default: ! 505: abort (); ! 506: } ! 507: } ! 508: ! 509: /* Return TRUE if this insn should stop the search for insn to fill delay ! 510: slots. LABELS_P indicates that labels should terminate the search. ! 511: In all cases, jumps terminate the search. */ ! 512: ! 513: static int ! 514: stop_search_p (insn, labels_p) ! 515: rtx insn; ! 516: int labels_p; ! 517: { ! 518: if (insn == 0) ! 519: return 1; ! 520: ! 521: switch (GET_CODE (insn)) ! 522: { ! 523: case NOTE: ! 524: case CALL_INSN: ! 525: return 0; ! 526: ! 527: case CODE_LABEL: ! 528: return labels_p; ! 529: ! 530: case JUMP_INSN: ! 531: case BARRIER: ! 532: return 1; ! 533: ! 534: case INSN: ! 535: /* OK unless it contains a delay slot or is an `asm' insn of some type. ! 536: We don't know anything about these. */ ! 537: return (GET_CODE (PATTERN (insn)) == SEQUENCE ! 538: || GET_CODE (PATTERN (insn)) == ASM_INPUT ! 539: || asm_noperands (PATTERN (insn)) >= 0); ! 540: ! 541: default: ! 542: abort (); ! 543: } ! 544: } ! 545: ! 546: /* Return TRUE if any resources are marked in both RES1 and RES2 or if either ! 547: resource set contains a volatile memory reference. Otherwise, return FALSE. */ ! 548: ! 549: static int ! 550: resource_conflicts_p (res1, res2) ! 551: struct resources *res1, *res2; ! 552: { ! 553: if ((res1->cc && res2->cc) || (res1->memory && res2->memory) ! 554: || res1->volatil || res2->volatil) ! 555: return 1; ! 556: ! 557: #ifdef HARD_REG_SET ! 558: return (res1->regs & res2->regs) != HARD_CONST (0); ! 559: #else ! 560: { ! 561: int i; ! 562: ! 563: for (i = 0; i < HARD_REG_SET_LONGS; i++) ! 564: if ((res1->regs[i] & res2->regs[i]) != 0) ! 565: return 1; ! 566: return 0; ! 567: } ! 568: #endif ! 569: } ! 570: ! 571: /* Return TRUE if any resource marked in RES, a `struct resources', is ! 572: referenced by INSN. If INCLUDE_CALLED_ROUTINE is set, return if the called ! 573: routine is using those resources. ! 574: ! 575: We compute this by computing all the resources referenced by INSN and ! 576: seeing if this conflicts with RES. It might be faster to directly check ! 577: ourselves, and this is the way it used to work, but it means duplicating ! 578: a large block of complex code. */ ! 579: ! 580: static int ! 581: insn_references_resource_p (insn, res, include_called_routine) ! 582: register rtx insn; ! 583: register struct resources *res; ! 584: int include_called_routine; ! 585: { ! 586: struct resources insn_res; ! 587: ! 588: CLEAR_RESOURCE (&insn_res); ! 589: mark_referenced_resources (insn, &insn_res, include_called_routine); ! 590: return resource_conflicts_p (&insn_res, res); ! 591: } ! 592: ! 593: /* Return TRUE if INSN modifies resources that are marked in RES. ! 594: INCLUDE_CALLED_ROUTINE is set if the actions of that routine should be ! 595: included. CC0 is only modified if it is explicitly set; see comments ! 596: in front of mark_set_resources for details. */ ! 597: ! 598: static int ! 599: insn_sets_resource_p (insn, res, include_called_routine) ! 600: register rtx insn; ! 601: register struct resources *res; ! 602: int include_called_routine; ! 603: { ! 604: struct resources insn_sets; ! 605: ! 606: CLEAR_RESOURCE (&insn_sets); ! 607: mark_set_resources (insn, &insn_sets, include_called_routine); ! 608: return resource_conflicts_p (&insn_sets, res); ! 609: } ! 610: ! 611: /* Find a label at the end of the function or before a RETURN. If there is ! 612: none, make one. */ ! 613: ! 614: static rtx ! 615: find_end_label () ! 616: { ! 617: rtx insn; ! 618: ! 619: /* If we found one previously, return it. */ ! 620: if (end_of_function_label) ! 621: return end_of_function_label; ! 622: ! 623: /* Otherwise, see if there is a label at the end of the function. If there ! 624: is, it must be that RETURN insns aren't needed, so that is our return ! 625: label and we don't have to do anything else. */ ! 626: ! 627: insn = get_last_insn (); ! 628: while (GET_CODE (insn) == NOTE ! 629: || (GET_CODE (insn) == INSN ! 630: && (GET_CODE (PATTERN (insn)) == USE ! 631: || GET_CODE (PATTERN (insn)) == CLOBBER))) ! 632: insn = PREV_INSN (insn); ! 633: ! 634: if (GET_CODE (insn) == CODE_LABEL) ! 635: end_of_function_label = insn; ! 636: else ! 637: { ! 638: /* Otherwise, make a new label and emit a RETURN and BARRIER, ! 639: if needed. */ ! 640: end_of_function_label = gen_label_rtx (); ! 641: LABEL_NUSES (end_of_function_label) = 0; ! 642: emit_label (end_of_function_label); ! 643: #ifdef HAVE_return ! 644: if (HAVE_return) ! 645: { ! 646: emit_jump_insn (gen_return ()); ! 647: emit_barrier (); ! 648: } ! 649: #endif ! 650: } ! 651: ! 652: /* Show one additional use for this label so it won't go away until ! 653: we are done. */ ! 654: ++LABEL_NUSES (end_of_function_label); ! 655: ! 656: return end_of_function_label; ! 657: } ! 658: ! 659: /* Put INSN and LIST together in a SEQUENCE rtx of LENGTH, and replace ! 660: the pattern of INSN with the SEQUENCE. ! 661: ! 662: Chain the insns so that NEXT_INSN of each insn in the sequence points to ! 663: the next and NEXT_INSN of the last insn in the sequence points to ! 664: the first insn after the sequence. Similarly for PREV_INSN. This makes ! 665: it easier to scan all insns. ! 666: ! 667: Returns the SEQUENCE that replaces INSN. */ ! 668: ! 669: static rtx ! 670: emit_delay_sequence (insn, list, length, avail) ! 671: rtx insn; ! 672: rtx list; ! 673: int length; ! 674: int avail; ! 675: { ! 676: register int i = 1; ! 677: register rtx li; ! 678: int had_barrier = 0; ! 679: ! 680: /* Allocate the the rtvec to hold the insns and the SEQUENCE. */ ! 681: rtvec seqv = rtvec_alloc (length + 1); ! 682: rtx seq = gen_rtx (SEQUENCE, VOIDmode, seqv); ! 683: rtx seq_insn = make_insn_raw (seq); ! 684: rtx first = get_insns (); ! 685: rtx last = get_last_insn (); ! 686: ! 687: /* Make a copy of the insn having delay slots. */ ! 688: rtx delay_insn = copy_rtx (insn); ! 689: ! 690: /* If INSN is followed by a BARRIER, delete the BARRIER since it will only ! 691: confuse further processing. Update LAST in case it was the last insn. ! 692: We will put the BARRIER back in later. */ ! 693: if (NEXT_INSN (insn) && GET_CODE (NEXT_INSN (insn)) == BARRIER) ! 694: { ! 695: delete_insn (NEXT_INSN (insn)); ! 696: last = get_last_insn (); ! 697: had_barrier = 1; ! 698: } ! 699: ! 700: /* Splice our SEQUENCE into the insn stream where INSN used to be. */ ! 701: NEXT_INSN (seq_insn) = NEXT_INSN (insn); ! 702: PREV_INSN (seq_insn) = PREV_INSN (insn); ! 703: ! 704: if (insn == last) ! 705: set_new_first_and_last_insn (first, seq_insn); ! 706: else ! 707: PREV_INSN (NEXT_INSN (seq_insn)) = seq_insn; ! 708: ! 709: if (insn == first) ! 710: set_new_first_and_last_insn (seq_insn, last); ! 711: else ! 712: NEXT_INSN (PREV_INSN (seq_insn)) = seq_insn; ! 713: ! 714: /* Build our SEQUENCE and rebuild the insn chain. */ ! 715: XVECEXP (seq, 0, 0) = delay_insn; ! 716: INSN_DELETED_P (delay_insn) = 0; ! 717: PREV_INSN (delay_insn) = PREV_INSN (seq_insn); ! 718: ! 719: for (li = list; li; li = XEXP (li, 1), i++) ! 720: { ! 721: rtx tem = XEXP (li, 0); ! 722: rtx note; ! 723: ! 724: /* Show that this copy of the insn isn't deleted. */ ! 725: INSN_DELETED_P (tem) = 0; ! 726: ! 727: XVECEXP (seq, 0, i) = tem; ! 728: PREV_INSN (tem) = XVECEXP (seq, 0, i - 1); ! 729: NEXT_INSN (XVECEXP (seq, 0, i - 1)) = tem; ! 730: ! 731: /* Remove any REG_DEAD notes because we can't rely on them now ! 732: that the insn has been moved. */ ! 733: for (note = REG_NOTES (tem); note; note = XEXP (note, 1)) ! 734: if (REG_NOTE_KIND (note) == REG_DEAD) ! 735: XEXP (note, 0) = const0_rtx; ! 736: } ! 737: ! 738: NEXT_INSN (XVECEXP (seq, 0, length)) = NEXT_INSN (seq_insn); ! 739: ! 740: /* If the previous insn is a SEQUENCE, update the NEXT_INSN pointer on the ! 741: last insn in that SEQUENCE to point to us. Similarly for the first ! 742: insn in the following insn if it is a SEQUENCE. */ ! 743: ! 744: if (PREV_INSN (seq_insn) && GET_CODE (PREV_INSN (seq_insn)) == INSN ! 745: && GET_CODE (PATTERN (PREV_INSN (seq_insn))) == SEQUENCE) ! 746: NEXT_INSN (XVECEXP (PATTERN (PREV_INSN (seq_insn)), 0, ! 747: XVECLEN (PATTERN (PREV_INSN (seq_insn)), 0) - 1)) ! 748: = seq_insn; ! 749: ! 750: if (NEXT_INSN (seq_insn) && GET_CODE (NEXT_INSN (seq_insn)) == INSN ! 751: && GET_CODE (PATTERN (NEXT_INSN (seq_insn))) == SEQUENCE) ! 752: PREV_INSN (XVECEXP (PATTERN (NEXT_INSN (seq_insn)), 0, 0)) = seq_insn; ! 753: ! 754: /* If there used to be a BARRIER, put it back. */ ! 755: if (had_barrier) ! 756: emit_barrier_after (seq_insn); ! 757: ! 758: if (i != length + 1) ! 759: abort (); ! 760: ! 761: return seq_insn; ! 762: } ! 763: ! 764: /* Add INSN to DELAY_LIST and return the head of the new list. The list must ! 765: be in the order in which the insns are to be executed. */ ! 766: ! 767: static rtx ! 768: add_to_delay_list (insn, delay_list) ! 769: rtx insn; ! 770: rtx delay_list; ! 771: { ! 772: /* If we have an empty list, just make a new list element. */ ! 773: if (delay_list == 0) ! 774: return gen_rtx (INSN_LIST, VOIDmode, insn, 0); ! 775: ! 776: /* Otherwise this must be an INSN_LIST. Add INSN to the end of the ! 777: list. */ ! 778: XEXP (delay_list, 1) = add_to_delay_list (insn, XEXP (delay_list, 1)); ! 779: ! 780: return delay_list; ! 781: } ! 782: ! 783: #ifdef HAVE_cc0 ! 784: /* INSN uses CC0 and is being moved into a delay slot. Set up REG_CC_SETTER ! 785: and REG_CC_USER notes so we can find it. */ ! 786: ! 787: static void ! 788: link_cc0_insns (insn) ! 789: rtx insn; ! 790: { ! 791: rtx user = next_nonnote_insn (insn); ! 792: ! 793: if (GET_CODE (user) == INSN && GET_CODE (PATTERN (user)) == SEQUENCE) ! 794: user = XVECEXP (PATTERN (user), 0, 0); ! 795: ! 796: REG_NOTES (user) = gen_rtx (INSN_LIST, REG_CC_SETTER, insn, ! 797: REG_NOTES (user)); ! 798: REG_NOTES (insn) = gen_rtx (INSN_LIST, REG_CC_USER, user, REG_NOTES (insn)); ! 799: } ! 800: #endif ! 801: ! 802: /* Delete INSN from the the delay slot of the insn that it is in. This may ! 803: produce an insn without anything in its delay slots. */ ! 804: ! 805: static void ! 806: delete_from_delay_slot (insn) ! 807: rtx insn; ! 808: { ! 809: rtx trial, seq_insn, seq, prev; ! 810: rtx delay_list = 0; ! 811: int i; ! 812: ! 813: /* We first must find the insn containing the SEQUENCE with INSN in its ! 814: delay slot. Do this by finding an insn, TRIAL, where ! 815: PREV_INSN (NEXT_INSN (TRIAL)) != TRIAL. */ ! 816: ! 817: for (trial = insn; ! 818: PREV_INSN (NEXT_INSN (trial)) == trial; ! 819: trial = NEXT_INSN (trial)) ! 820: ; ! 821: ! 822: seq_insn = PREV_INSN (NEXT_INSN (trial)); ! 823: seq = PATTERN (seq_insn); ! 824: ! 825: /* Create a delay list consisting of all the insns other than the one ! 826: we are deleting (unless we were the only one). */ ! 827: if (XVECLEN (seq, 0) > 2) ! 828: for (i = 1; i < XVECLEN (seq, 0); i++) ! 829: if (XVECEXP (seq, 0, i) != insn) ! 830: delay_list = add_to_delay_list (XVECEXP (seq, 0, i), delay_list); ! 831: ! 832: /* Delete the old SEQUENCE, re-emit the insn that used to have the delay ! 833: list, and rebuild the delay list if non-empty. */ ! 834: prev = PREV_INSN (seq_insn); ! 835: trial = XVECEXP (seq, 0, 0); ! 836: delete_insn (seq_insn); ! 837: add_insn_after (trial, prev); ! 838: ! 839: if (GET_CODE (trial) == JUMP_INSN ! 840: && (simplejump_p (trial) || GET_CODE (PATTERN (trial)) == RETURN)) ! 841: emit_barrier_after (trial); ! 842: ! 843: /* If there are any delay insns, remit them. Otherwise clear the ! 844: annul flag. */ ! 845: if (delay_list) ! 846: trial = emit_delay_sequence (trial, delay_list, XVECLEN (seq, 0) - 2, 0); ! 847: else ! 848: INSN_ANNULLED_BRANCH_P (trial) = 0; ! 849: ! 850: INSN_FROM_TARGET_P (insn) = 0; ! 851: ! 852: /* Show we need to fill this insn again. */ ! 853: obstack_ptr_grow (&unfilled_slots_obstack, trial); ! 854: } ! 855: ! 856: /* Delete INSN, a JUMP_INSN. If it is a conditional jump, we must track down ! 857: the insn that sets CC0 for it and delete it too. */ ! 858: ! 859: static void ! 860: delete_scheduled_jump (insn) ! 861: rtx insn; ! 862: { ! 863: /* Delete the insn that sets cc0 for us. On machines without cc0, we could ! 864: delete the insn that sets the condition code, but it is hard to find it. ! 865: Since this case is rare anyway, don't bother trying; there would likely ! 866: be other insns that became dead anyway, which we wouldn't know to ! 867: delete. */ ! 868: ! 869: #ifdef HAVE_cc0 ! 870: if (reg_mentioned_p (cc0_rtx, insn)) ! 871: { ! 872: rtx note = find_reg_note (insn, REG_CC_SETTER, 0); ! 873: ! 874: /* If a reg-note was found, it points to an insn to set CC0. This ! 875: insn is in the delay list of some other insn. So delete it from ! 876: the delay list it was in. */ ! 877: if (note) ! 878: { ! 879: if (! FIND_REG_INC_NOTE (XEXP (note, 0), 0) ! 880: && sets_cc0_p (PATTERN (XEXP (note, 0))) == 1) ! 881: delete_from_delay_slot (XEXP (note, 0)); ! 882: } ! 883: else ! 884: { ! 885: /* The insn setting CC0 is our previous insn, but it may be in ! 886: a delay slot. It will be the last insn in the delay slot, if ! 887: it is. */ ! 888: rtx trial = previous_insn (insn); ! 889: if (GET_CODE (trial) == NOTE) ! 890: trial = prev_nonnote_insn (trial); ! 891: if (sets_cc0_p (PATTERN (trial)) != 1 ! 892: || FIND_REG_INC_NOTE (trial, 0)) ! 893: return; ! 894: if (PREV_INSN (NEXT_INSN (trial)) == trial) ! 895: delete_insn (trial); ! 896: else ! 897: delete_from_delay_slot (trial); ! 898: } ! 899: } ! 900: #endif ! 901: ! 902: delete_insn (insn); ! 903: } ! 904: ! 905: /* Counters for delay-slot filling. */ ! 906: ! 907: #define NUM_REORG_FUNCTIONS 2 ! 908: #define MAX_DELAY_HISTOGRAM 3 ! 909: #define MAX_REORG_PASSES 2 ! 910: ! 911: static int num_insns_needing_delays[NUM_REORG_FUNCTIONS][MAX_REORG_PASSES]; ! 912: ! 913: static int num_filled_delays[NUM_REORG_FUNCTIONS][MAX_DELAY_HISTOGRAM+1][MAX_REORG_PASSES]; ! 914: ! 915: static int reorg_pass_number; ! 916: ! 917: static void ! 918: note_delay_statistics (slots_filled, index) ! 919: int slots_filled, index; ! 920: { ! 921: num_insns_needing_delays[index][reorg_pass_number]++; ! 922: if (slots_filled > MAX_DELAY_HISTOGRAM) ! 923: slots_filled = MAX_DELAY_HISTOGRAM; ! 924: num_filled_delays[index][slots_filled][reorg_pass_number]++; ! 925: } ! 926: ! 927: #if defined(ANNUL_IFFALSE_SLOTS) || defined(ANNUL_IFTRUE_SLOTS) ! 928: ! 929: /* Optimize the following cases: ! 930: ! 931: 1. When a conditional branch skips over only one instruction, ! 932: use an annulling branch and put that insn in the delay slot. ! 933: Use either a branch that annulls when the condition if true or ! 934: invert the test with a branch that annulls when the condition is ! 935: false. This saves insns, since otherwise we must copy an insn ! 936: from the L1 target. ! 937: ! 938: (orig) (skip) (otherwise) ! 939: Bcc.n L1 Bcc',a L1 Bcc,a L1' ! 940: insn insn insn2 ! 941: L1: L1: L1: ! 942: insn2 insn2 insn2 ! 943: insn3 insn3 L1': ! 944: insn3 ! 945: ! 946: 2. When a conditional branch skips over only one instruction, ! 947: and after that, it unconditionally branches somewhere else, ! 948: perform the similar optimization. This saves executing the ! 949: second branch in the case where the inverted condition is true. ! 950: ! 951: Bcc.n L1 Bcc',a L2 ! 952: insn insn ! 953: L1: L1: ! 954: Bra L2 Bra L2 ! 955: ! 956: INSN is a JUMP_INSN. ! 957: ! 958: This should be expanded to skip over N insns, where N is the number ! 959: of delay slots required. */ ! 960: ! 961: static rtx ! 962: optimize_skip (insn) ! 963: register rtx insn; ! 964: { ! 965: register rtx trial = next_nonnote_insn (insn); ! 966: rtx next_trial = next_active_insn (trial); ! 967: rtx delay_list = 0; ! 968: rtx target_label; ! 969: ! 970: if (trial == 0 ! 971: || GET_CODE (trial) != INSN ! 972: || GET_CODE (PATTERN (trial)) == SEQUENCE ! 973: || recog_memoized (trial) < 0 ! 974: || (! eligible_for_annul_false (insn, 0, trial) ! 975: && ! eligible_for_annul_true (insn, 0, trial))) ! 976: return 0; ! 977: ! 978: /* There are two cases where we are just executing one insn (we assume ! 979: here that a branch requires only one insn; this should be generalized ! 980: at some point): Where the branch goes around a single insn or where ! 981: we have one insn followed by a branch to the same label we branch to. ! 982: In both of these cases, inverting the jump and annulling the delay ! 983: slot give the same effect in fewer insns. */ ! 984: if ((next_trial == next_active_insn (JUMP_LABEL (insn))) ! 985: || (next_trial != 0 ! 986: && GET_CODE (next_trial) == JUMP_INSN ! 987: && JUMP_LABEL (insn) == JUMP_LABEL (next_trial) ! 988: && (simplejump_p (next_trial) ! 989: || GET_CODE (PATTERN (next_trial)) == RETURN))) ! 990: { ! 991: if (eligible_for_annul_false (insn, 0, trial)) ! 992: { ! 993: if (invert_jump (insn, JUMP_LABEL (insn))) ! 994: INSN_FROM_TARGET_P (trial) = 1; ! 995: else if (! eligible_for_annul_true (insn, 0, trial)) ! 996: return 0; ! 997: } ! 998: ! 999: delay_list = add_to_delay_list (trial, 0); ! 1000: next_trial = next_active_insn (trial); ! 1001: update_block (trial, trial); ! 1002: delete_insn (trial); ! 1003: ! 1004: /* Also, if we are targeting an unconditional ! 1005: branch, thread our jump to the target of that branch. Don't ! 1006: change this into a RETURN here, because it may not accept what ! 1007: we have in the delay slot. We'll fix this up later. */ ! 1008: if (next_trial && GET_CODE (next_trial) == JUMP_INSN ! 1009: && (simplejump_p (next_trial) ! 1010: || GET_CODE (PATTERN (next_trial)) == RETURN)) ! 1011: { ! 1012: target_label = JUMP_LABEL (next_trial); ! 1013: if (target_label == 0) ! 1014: target_label = find_end_label (); ! 1015: redirect_jump (insn, target_label); ! 1016: } ! 1017: ! 1018: INSN_ANNULLED_BRANCH_P (insn) = 1; ! 1019: } ! 1020: ! 1021: return delay_list; ! 1022: } ! 1023: #endif ! 1024: ! 1025: /* Return truth value of the statement that this branch ! 1026: is mostly taken. If we think that the branch is extremely likely ! 1027: to be taken, we return 2. If the branch is slightly more likely to be ! 1028: taken, return 1. Otherwise, return 0. ! 1029: ! 1030: CONDITION, if non-zero, is the condition that JUMP_INSN is testing. */ ! 1031: ! 1032: static int ! 1033: mostly_true_jump (jump_insn, condition) ! 1034: rtx jump_insn, condition; ! 1035: { ! 1036: rtx target_label = JUMP_LABEL (jump_insn); ! 1037: rtx insn; ! 1038: ! 1039: /* If this is a conditional return insn, assume it won't return. */ ! 1040: if (target_label == 0) ! 1041: return 0; ! 1042: ! 1043: /* If TARGET_LABEL has no jumps between it and the end of the function, ! 1044: this is essentially a conditional return, so predict it as false. */ ! 1045: for (insn = NEXT_INSN (target_label); ! 1046: insn && GET_CODE (insn) != JUMP_INSN; ! 1047: insn = NEXT_INSN (insn)) ! 1048: ; ! 1049: ! 1050: if (insn == 0) ! 1051: return 0; ! 1052: ! 1053: /* If this is the test of a loop, it is very likely true. We scan backwards ! 1054: from the target label. If we find a NOTE_INSN_LOOP_BEG before the next ! 1055: real insn, we assume the branch is to the top of the loop. */ ! 1056: for (insn = PREV_INSN (target_label); ! 1057: insn && GET_CODE (insn) == NOTE; ! 1058: insn = PREV_INSN (insn)) ! 1059: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG) ! 1060: return 2; ! 1061: ! 1062: /* If we couldn't figure out what this jump was, assume it won't be ! 1063: taken. This should be rare. */ ! 1064: if (condition == 0) ! 1065: return 0; ! 1066: ! 1067: /* EQ tests are usually false and NE tests are usually true. Also, ! 1068: most quantities are positive, so we can make the appropriate guesses ! 1069: about signed comparisons against zero. */ ! 1070: switch (GET_CODE (condition)) ! 1071: { ! 1072: case CONST_INT: ! 1073: /* Unconditional branch. */ ! 1074: return 1; ! 1075: case EQ: ! 1076: return 0; ! 1077: case NE: ! 1078: return 1; ! 1079: case LE: ! 1080: case LT: ! 1081: if (XEXP (condition, 1) == const0_rtx) ! 1082: return 0; ! 1083: break; ! 1084: case GE: ! 1085: case GT: ! 1086: if (XEXP (condition, 1) == const0_rtx) ! 1087: return 1; ! 1088: break; ! 1089: } ! 1090: ! 1091: /* Predict backward branches usually take, forward branches usually not. If ! 1092: we don't know whether this is forward or backward, assume the branch ! 1093: will be taken, since most are. */ ! 1094: return (INSN_UID (jump_insn) > max_uid || INSN_UID (target_label) > max_uid ! 1095: || (uid_to_ruid[INSN_UID (jump_insn)] ! 1096: > uid_to_ruid[INSN_UID (target_label)]));; ! 1097: } ! 1098: ! 1099: /* Return the condition under which INSN will branch to TARGET. If TARGET ! 1100: is zero, return the condition under which INSN will return. If INSN is ! 1101: an unconditional branch, return const_true_rtx. If INSN isn't a simple ! 1102: type of jump, or it doesn't go to TARGET, return 0. */ ! 1103: ! 1104: static rtx ! 1105: get_branch_condition (insn, target) ! 1106: rtx insn; ! 1107: rtx target; ! 1108: { ! 1109: rtx pat = PATTERN (insn); ! 1110: rtx src; ! 1111: ! 1112: if (GET_CODE (pat) == RETURN) ! 1113: return target == 0 ? const_true_rtx : 0; ! 1114: ! 1115: else if (GET_CODE (pat) != SET || SET_DEST (pat) != pc_rtx) ! 1116: return 0; ! 1117: ! 1118: src = SET_SRC (pat); ! 1119: if (GET_CODE (src) == LABEL_REF && XEXP (src, 0) == target) ! 1120: return const_true_rtx; ! 1121: ! 1122: else if (GET_CODE (src) == IF_THEN_ELSE ! 1123: && ((target == 0 && GET_CODE (XEXP (src, 1)) == RETURN) ! 1124: || (GET_CODE (XEXP (src, 1)) == LABEL_REF ! 1125: && XEXP (XEXP (src, 1), 0) == target)) ! 1126: && XEXP (src, 2) == pc_rtx) ! 1127: return XEXP (src, 0); ! 1128: ! 1129: else if (GET_CODE (src) == IF_THEN_ELSE ! 1130: && ((target == 0 && GET_CODE (XEXP (src, 2)) == RETURN) ! 1131: || (GET_CODE (XEXP (src, 2)) == LABEL_REF ! 1132: && XEXP (XEXP (src, 2), 0) == target)) ! 1133: && XEXP (src, 1) == pc_rtx) ! 1134: return gen_rtx (reverse_condition (GET_CODE (XEXP (src, 0))), ! 1135: GET_MODE (XEXP (src, 0)), ! 1136: XEXP (XEXP (src, 0), 0), XEXP (XEXP (src, 0), 1)); ! 1137: } ! 1138: ! 1139: /* Return non-zero if CONDITION is more strict than the condition of ! 1140: INSN, i.e., if INSN will always branch if CONDITION is true. */ ! 1141: ! 1142: static int ! 1143: condition_dominates_p (condition, insn) ! 1144: rtx condition; ! 1145: rtx insn; ! 1146: { ! 1147: rtx other_condition = get_branch_condition (insn, JUMP_LABEL (insn)); ! 1148: enum rtx_code code = GET_CODE (condition); ! 1149: enum rtx_code other_code; ! 1150: ! 1151: if (rtx_equal_p (condition, other_condition) ! 1152: || other_condition == const_true_rtx) ! 1153: return 1; ! 1154: ! 1155: else if (condition == const_true_rtx || other_condition == 0) ! 1156: return 0; ! 1157: ! 1158: other_code = GET_CODE (other_condition); ! 1159: if (GET_RTX_LENGTH (code) != 2 || GET_RTX_LENGTH (other_code) != 2 ! 1160: || ! rtx_equal_p (XEXP (condition, 0), XEXP (other_condition, 0)) ! 1161: || ! rtx_equal_p (XEXP (condition, 1), XEXP (other_condition, 1))) ! 1162: return 0; ! 1163: ! 1164: return comparison_dominates_p (code, other_code); ! 1165: } ! 1166: ! 1167: /* INSN branches to an insn whose pattern SEQ is a SEQUENCE. Given that ! 1168: the condition tested by INSN is CONDITION and the resources shown in ! 1169: OTHER_NEEDED are needed after INSN, see whether INSN can take all the insns ! 1170: from SEQ's delay list, in addition to whatever insns it may execute ! 1171: (in DELAY_LIST). SETS and NEEDED are denote resources already set and ! 1172: needed while searching for delay slot insns. Return the concatenated ! 1173: delay list if possible, otherwise, return 0. ! 1174: ! 1175: SLOTS_TO_FILL is the total number of slots required by INSN, and ! 1176: PSLOTS_FILLED points to the number filled so far (also the number of ! 1177: insns in DELAY_LIST). It is updated with the number that have been ! 1178: filled from the SEQUENCE, if any. ! 1179: ! 1180: PANNUL_P points to a non-zero value if we already know that we need ! 1181: to annul INSN. If this routine determines that annulling is needed, ! 1182: it may set that value non-zero. ! 1183: ! 1184: PNEW_THREAD points to a location that is to receive the place at which ! 1185: execution should continue. */ ! 1186: ! 1187: static rtx ! 1188: steal_delay_list_from_target (insn, condition, seq, delay_list, ! 1189: sets, needed, other_needed, ! 1190: slots_to_fill, pslots_filled, pannul_p, ! 1191: pnew_thread) ! 1192: rtx insn, condition; ! 1193: rtx seq; ! 1194: rtx delay_list; ! 1195: struct resources *sets, *needed, *other_needed; ! 1196: int slots_to_fill; ! 1197: int *pslots_filled; ! 1198: int *pannul_p; ! 1199: rtx *pnew_thread; ! 1200: { ! 1201: rtx temp; ! 1202: int slots_remaining = slots_to_fill - *pslots_filled; ! 1203: int total_slots_filled = *pslots_filled; ! 1204: rtx new_delay_list = 0; ! 1205: int must_annul = *pannul_p; ! 1206: int i; ! 1207: ! 1208: /* We can't do anything if there are more delay slots in SEQ than we ! 1209: can handle, or if we don't know that it will be a taken branch. ! 1210: ! 1211: We know that it will be a taken branch if it is either an unconditional ! 1212: branch or a conditional branch with a stricter branch condition. */ ! 1213: ! 1214: if (XVECLEN (seq, 0) - 1 > slots_remaining ! 1215: || ! condition_dominates_p (condition, XVECEXP (seq, 0, 0))) ! 1216: return delay_list; ! 1217: ! 1218: for (i = 1; i < XVECLEN (seq, 0); i++) ! 1219: { ! 1220: rtx trial = XVECEXP (seq, 0, i); ! 1221: ! 1222: if (insn_references_resource_p (trial, sets, 0) ! 1223: || insn_sets_resource_p (trial, needed, 0) ! 1224: || insn_sets_resource_p (trial, sets, 0) ! 1225: #ifdef HAVE_cc0 ! 1226: /* If TRIAL sets CC0, we can't copy it, so we can't steal this ! 1227: delay list. */ ! 1228: || find_reg_note (trial, REG_CC_USER, 0) ! 1229: #endif ! 1230: /* If TRIAL is from the fallthrough code of an annulled branch insn ! 1231: in SEQ, we cannot use it. */ ! 1232: || (INSN_ANNULLED_BRANCH_P (XVECEXP (seq, 0, 0)) ! 1233: && ! INSN_FROM_TARGET_P (trial))) ! 1234: return delay_list; ! 1235: ! 1236: /* If this insn was already done (usually in a previous delay slot), ! 1237: pretend we put it in our delay slot. */ ! 1238: if (redundant_insn_p (trial, insn, new_delay_list)) ! 1239: continue; ! 1240: ! 1241: if (! must_annul ! 1242: && ((condition == const_true_rtx ! 1243: || (! insn_sets_resource_p (trial, other_needed, 0) ! 1244: && ! may_trap_p (PATTERN (trial))))) ! 1245: ? eligible_for_delay (insn, total_slots_filled, trial) ! 1246: : (must_annul = 1, ! 1247: eligible_for_annul_false (insn, total_slots_filled, trial))) ! 1248: { ! 1249: temp = copy_rtx (trial); ! 1250: INSN_FROM_TARGET_P (temp) = 1; ! 1251: new_delay_list = add_to_delay_list (temp, new_delay_list); ! 1252: total_slots_filled++; ! 1253: ! 1254: if (--slots_remaining == 0) ! 1255: break; ! 1256: } ! 1257: else ! 1258: return delay_list; ! 1259: } ! 1260: ! 1261: /* Show the place to which we will be branching. */ ! 1262: *pnew_thread = next_active_insn (JUMP_LABEL (XVECEXP (seq, 0, 0))); ! 1263: ! 1264: /* Add any new insns to the delay list and update the count of the ! 1265: number of slots filled. */ ! 1266: *pslots_filled = total_slots_filled; ! 1267: *pannul_p = must_annul; ! 1268: ! 1269: if (delay_list == 0) ! 1270: return new_delay_list; ! 1271: ! 1272: for (temp = new_delay_list; temp; temp = XEXP (temp, 1)) ! 1273: delay_list = add_to_delay_list (XEXP (temp, 0), delay_list); ! 1274: ! 1275: return delay_list; ! 1276: } ! 1277: ! 1278: /* Similar to steal_delay_list_from_target except that SEQ is on the ! 1279: fallthrough path of INSN. Here we only do something if the delay insn ! 1280: of SEQ is an unconditional branch. In that case we steal its delay slot ! 1281: for INSN since unconditional branches are much easier to fill. */ ! 1282: ! 1283: static rtx ! 1284: steal_delay_list_from_fallthrough (insn, condition, seq, ! 1285: delay_list, sets, needed, other_needed, ! 1286: slots_to_fill, pslots_filled, pannul_p) ! 1287: rtx insn, condition; ! 1288: rtx seq; ! 1289: rtx delay_list; ! 1290: struct resources *sets, *needed, *other_needed; ! 1291: int slots_to_fill; ! 1292: int *pslots_filled; ! 1293: int *pannul_p; ! 1294: { ! 1295: int i; ! 1296: ! 1297: /* We can't do anything if SEQ's delay insn isn't an ! 1298: unconditional branch. */ ! 1299: ! 1300: if (! simplejump_p (XVECEXP (seq, 0, 0)) ! 1301: && GET_CODE (PATTERN (XVECEXP (seq, 0, 0))) != RETURN) ! 1302: return delay_list; ! 1303: ! 1304: for (i = 1; i < XVECLEN (seq, 0); i++) ! 1305: { ! 1306: rtx trial = XVECEXP (seq, 0, i); ! 1307: ! 1308: /* If TRIAL sets CC0, stealing it will move it too far from the use ! 1309: of CC0. */ ! 1310: if (insn_references_resource_p (trial, sets, 0) ! 1311: || insn_sets_resource_p (trial, needed, 0) ! 1312: || insn_sets_resource_p (trial, sets, 0) ! 1313: #ifdef HAVE_cc0 ! 1314: || sets_cc0_p (PATTERN (trial)) ! 1315: #endif ! 1316: ) ! 1317: ! 1318: break; ! 1319: ! 1320: /* If this insn was already done, we don't need it. */ ! 1321: if (redundant_insn_p (trial, insn, delay_list)) ! 1322: { ! 1323: delete_from_delay_slot (trial); ! 1324: continue; ! 1325: } ! 1326: ! 1327: if (! *pannul_p ! 1328: && ((condition == const_true_rtx ! 1329: || (! insn_sets_resource_p (trial, other_needed, 0) ! 1330: && ! may_trap_p (PATTERN (trial))))) ! 1331: ? eligible_for_delay (insn, *pslots_filled, trial) ! 1332: : (*pannul_p = 1, ! 1333: eligible_for_annul_true (insn, *pslots_filled, trial))) ! 1334: { ! 1335: delete_from_delay_slot (trial); ! 1336: delay_list = add_to_delay_list (trial, delay_list); ! 1337: ! 1338: if (++(*pslots_filled) == slots_to_fill) ! 1339: break; ! 1340: } ! 1341: else ! 1342: break; ! 1343: } ! 1344: ! 1345: return delay_list; ! 1346: } ! 1347: ! 1348: /* Try merging insns starting at THREAD which match exactly the insns in ! 1349: INSN's delay list. ! 1350: ! 1351: If all insns were matched and the insn was previously annulling, the ! 1352: annul bit will be cleared. ! 1353: ! 1354: For each insn that is merged, if the branch is or will be non-annulling, ! 1355: we delete the merged insn. */ ! 1356: ! 1357: static void ! 1358: try_merge_delay_insns (insn, thread) ! 1359: rtx insn, thread; ! 1360: { ! 1361: rtx trial, next_trial; ! 1362: rtx delay_insn = XVECEXP (PATTERN (insn), 0, 0); ! 1363: int annul_p = INSN_ANNULLED_BRANCH_P (delay_insn); ! 1364: int slot_number = 1; ! 1365: int num_slots = XVECLEN (PATTERN (insn), 0); ! 1366: rtx next_to_match = XVECEXP (PATTERN (insn), 0, slot_number); ! 1367: struct resources set, needed; ! 1368: rtx merged_insns = 0; ! 1369: int i; ! 1370: ! 1371: CLEAR_RESOURCE (&needed); ! 1372: CLEAR_RESOURCE (&set); ! 1373: ! 1374: /* If this is not an annulling branch, take into account anything needed in ! 1375: NEXT_TO_MATCH. This prevents two increments from being incorrectly ! 1376: folded into one. If we are annulling, this would be the correct ! 1377: thing to do. (The alternative, looking at things set in NEXT_TO_MATCH ! 1378: will essentially disable this optimization. This method is somewhat of ! 1379: a kludge, but I don't see a better way.) */ ! 1380: if (! annul_p) ! 1381: mark_referenced_resources (next_to_match, &needed, 1); ! 1382: ! 1383: for (trial = thread; !stop_search_p (trial, 1); trial = next_trial) ! 1384: { ! 1385: rtx pat = PATTERN (trial); ! 1386: ! 1387: next_trial = next_nonnote_insn (trial); ! 1388: ! 1389: /* TRIAL must be a CALL_INSN or INSN. Skip USE and CLOBBER. */ ! 1390: if (GET_CODE (trial) == INSN ! 1391: && (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER)) ! 1392: continue; ! 1393: ! 1394: if (GET_CODE (next_to_match) == GET_CODE (trial) ! 1395: #ifdef HAVE_cc0 ! 1396: /* We can't share an insn that sets cc0. */ ! 1397: && ! sets_cc0_p (pat) ! 1398: #endif ! 1399: && ! insn_references_resource_p (trial, &set, 1) ! 1400: && ! insn_sets_resource_p (trial, &set, 1) ! 1401: && ! insn_sets_resource_p (trial, &needed, 1) ! 1402: && (trial = try_split (pat, trial, 0)) != 0 ! 1403: && rtx_equal_p (PATTERN (next_to_match), PATTERN (trial)) ! 1404: /* Have to test this condition if annul condition is different ! 1405: from (and less restrictive than) non-annulling one. */ ! 1406: && eligible_for_delay (delay_insn, slot_number - 1, trial)) ! 1407: { ! 1408: next_trial = next_nonnote_insn (trial); ! 1409: ! 1410: if (! annul_p) ! 1411: { ! 1412: update_block (trial, thread); ! 1413: delete_insn (trial); ! 1414: INSN_FROM_TARGET_P (next_to_match) = 0; ! 1415: } ! 1416: else ! 1417: merged_insns = gen_rtx (INSN_LIST, VOIDmode, trial, merged_insns); ! 1418: ! 1419: if (++slot_number == num_slots) ! 1420: break; ! 1421: ! 1422: next_to_match = XVECEXP (PATTERN (insn), 0, slot_number); ! 1423: if (! annul_p) ! 1424: mark_referenced_resources (next_to_match, &needed, 1); ! 1425: } ! 1426: ! 1427: mark_set_resources (trial, &set, 1); ! 1428: mark_referenced_resources (trial, &needed, 1); ! 1429: } ! 1430: ! 1431: /* See if we stopped on a filled insn. If we did, try to see if its ! 1432: delay slots match. */ ! 1433: if (slot_number != num_slots ! 1434: && trial && GET_CODE (trial) == INSN ! 1435: && GET_CODE (PATTERN (trial)) == SEQUENCE ! 1436: && ! INSN_ANNULLED_BRANCH_P (XVECEXP (PATTERN (trial), 0, 0))) ! 1437: { ! 1438: rtx pat = PATTERN (trial); ! 1439: ! 1440: for (i = 1; i < XVECLEN (pat, 0); i++) ! 1441: { ! 1442: rtx dtrial = XVECEXP (pat, 0, i); ! 1443: ! 1444: if (! insn_references_resource_p (dtrial, &set, 1) ! 1445: && ! insn_sets_resource_p (dtrial, &set, 1) ! 1446: && ! insn_sets_resource_p (dtrial, &needed, 1) ! 1447: #ifdef HAVE_cc0 ! 1448: && ! sets_cc0_p (PATTERN (dtrial)) ! 1449: #endif ! 1450: && rtx_equal_p (PATTERN (next_to_match), PATTERN (dtrial)) ! 1451: && eligible_for_delay (delay_insn, slot_number - 1, dtrial)) ! 1452: { ! 1453: if (! annul_p) ! 1454: { ! 1455: update_block (dtrial, thread); ! 1456: delete_from_delay_slot (dtrial); ! 1457: INSN_FROM_TARGET_P (next_to_match) = 0; ! 1458: } ! 1459: else ! 1460: merged_insns = gen_rtx (INSN_LIST, SImode, dtrial, ! 1461: merged_insns); ! 1462: ! 1463: if (++slot_number == num_slots) ! 1464: break; ! 1465: ! 1466: next_to_match = XVECEXP (PATTERN (insn), 0, slot_number); ! 1467: } ! 1468: } ! 1469: } ! 1470: ! 1471: /* If all insns in the delay slot have been matched and we were previously ! 1472: annulling the branch, we need not any more. In that case delete all the ! 1473: merged insns. Also clear the INSN_FROM_TARGET_P bit of each insn the ! 1474: the delay list so that we know that it isn't only being used at the ! 1475: target. */ ! 1476: if (next_to_match == 0 && annul_p) ! 1477: { ! 1478: for (; merged_insns; merged_insns = XEXP (merged_insns, 1)) ! 1479: { ! 1480: if (GET_MODE (merged_insns) == SImode) ! 1481: { ! 1482: update_block (XEXP (merged_insns, 0), thread); ! 1483: delete_from_delay_slot (XEXP (merged_insns, 0)); ! 1484: } ! 1485: else ! 1486: { ! 1487: update_block (XEXP (merged_insns, 0), thread); ! 1488: delete_insn (XEXP (merged_insns, 0)); ! 1489: } ! 1490: } ! 1491: ! 1492: INSN_ANNULLED_BRANCH_P (delay_insn) = 0; ! 1493: ! 1494: for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++) ! 1495: INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i)) = 0; ! 1496: } ! 1497: } ! 1498: ! 1499: /* See if INSN is redundant with an insn in front of TARGET. Often this ! 1500: is called when INSN is a candidate for a delay slot of TARGET. ! 1501: DELAY_LIST are insns that will be placed in delay slots of TARGET in front ! 1502: of INSN. Often INSN will be redundant with an insn in a delay slot of ! 1503: some previous insn. This happens when we have a series of branches to the ! 1504: same label; in that case the first insn at the target might want to go ! 1505: into each of the delay slots. ! 1506: ! 1507: If we are not careful, this routine can take up a significant fraction ! 1508: of the total compilation time (4%), but only wins rarely. Hence we ! 1509: speed this routine up by making two passes. The first pass goes back ! 1510: until it hits a label and sees if it find an insn with an identical ! 1511: pattern. Only in this (relatively rare) event does it check for ! 1512: data conflicts. ! 1513: ! 1514: We do not split insns we encounter. This could cause us not to find a ! 1515: redundant insn, but the cost of splitting seems greater than the possible ! 1516: gain in rare cases. */ ! 1517: ! 1518: static int ! 1519: redundant_insn_p (insn, target, delay_list) ! 1520: rtx insn; ! 1521: rtx target; ! 1522: rtx delay_list; ! 1523: { ! 1524: rtx target_main = target; ! 1525: rtx ipat = PATTERN (insn); ! 1526: rtx trial, pat; ! 1527: struct resources needed, set; ! 1528: int i; ! 1529: ! 1530: /* Scan backwards looking for a match. */ ! 1531: for (trial = PREV_INSN (target); trial; trial = PREV_INSN (trial)) ! 1532: { ! 1533: if (GET_CODE (trial) == CODE_LABEL) ! 1534: return 0; ! 1535: ! 1536: if (GET_CODE (trial) != INSN && GET_CODE (trial) != JUMP_INSN ! 1537: && GET_CODE (trial) != JUMP_INSN) ! 1538: continue; ! 1539: ! 1540: pat = PATTERN (trial); ! 1541: if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER) ! 1542: continue; ! 1543: ! 1544: if (GET_CODE (pat) == SEQUENCE) ! 1545: { ! 1546: /* Stop for a CALL and its delay slots because it difficult to track ! 1547: its resource needs correctly. */ ! 1548: if (GET_CODE (XVECEXP (pat, 0, 0)) == CALL_INSN) ! 1549: return 0; ! 1550: ! 1551: for (i = XVECLEN (pat, 0) - 1; i > 0; i--) ! 1552: if (GET_CODE (XVECEXP (pat, 0, i)) == GET_CODE (insn) ! 1553: && rtx_equal_p (PATTERN (XVECEXP (pat, 0, i)), ipat)) ! 1554: break; ! 1555: ! 1556: /* If found a match, exit this loop early. */ ! 1557: if (i > 0) ! 1558: break; ! 1559: } ! 1560: ! 1561: else if (GET_CODE (trial) == GET_CODE (insn) && rtx_equal_p (pat, ipat)) ! 1562: break; ! 1563: } ! 1564: ! 1565: /* If we didn't find an insn that matches, return 0. */ ! 1566: if (trial == 0) ! 1567: return 0; ! 1568: ! 1569: /* See what resources this insn sets and needs. If they overlap, or ! 1570: if this insn references CC0, it can't be redundant. */ ! 1571: ! 1572: CLEAR_RESOURCE (&needed); ! 1573: CLEAR_RESOURCE (&set); ! 1574: mark_set_resources (insn, &set, 1); ! 1575: mark_referenced_resources (insn, &needed, 1); ! 1576: ! 1577: /* If TARGET is a SEQUENCE, get the main insn. */ ! 1578: if (GET_CODE (target) == INSN && GET_CODE (PATTERN (target)) == SEQUENCE) ! 1579: target_main = XVECEXP (PATTERN (target), 0, 0); ! 1580: ! 1581: if (resource_conflicts_p (&needed, &set) ! 1582: #ifdef HAVE_cc0 ! 1583: || reg_mentioned_p (cc0_rtx, ipat) ! 1584: #endif ! 1585: /* The insn requiring the delay may not set anything needed or set by ! 1586: INSN. */ ! 1587: || insn_sets_resource_p (target_main, &needed, 1) ! 1588: || insn_sets_resource_p (target_main, &set, 1)) ! 1589: return 0; ! 1590: ! 1591: /* Insns we pass may not set either NEEDED or SET, so merge them for ! 1592: simpler tests. */ ! 1593: needed.memory |= set.memory; ! 1594: IOR_HARD_REG_SET (needed.regs, set.regs); ! 1595: ! 1596: /* This insn isn't redundant if it conflicts with an insn that either is ! 1597: or will be in a delay slot of TARGET. */ ! 1598: ! 1599: while (delay_list) ! 1600: { ! 1601: if (insn_sets_resource_p (XEXP (delay_list, 0), &needed, 1)) ! 1602: return 0; ! 1603: delay_list = XEXP (delay_list, 1); ! 1604: } ! 1605: ! 1606: if (GET_CODE (target) == INSN && GET_CODE (PATTERN (target)) == SEQUENCE) ! 1607: for (i = 1; i < XVECLEN (PATTERN (target), 0); i++) ! 1608: if (insn_sets_resource_p (XVECEXP (PATTERN (target), 0, i), &needed, 1)) ! 1609: return 0; ! 1610: ! 1611: /* Scan backwards until we reach a label or an insn that uses something ! 1612: INSN sets or sets something insn uses or sets. */ ! 1613: ! 1614: for (trial = PREV_INSN (target); ! 1615: trial && GET_CODE (trial) != CODE_LABEL; ! 1616: trial = PREV_INSN (trial)) ! 1617: { ! 1618: if (GET_CODE (trial) != INSN && GET_CODE (trial) != CALL_INSN ! 1619: && GET_CODE (trial) != JUMP_INSN) ! 1620: continue; ! 1621: ! 1622: pat = PATTERN (trial); ! 1623: if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER) ! 1624: continue; ! 1625: ! 1626: if (GET_CODE (pat) == SEQUENCE) ! 1627: { ! 1628: /* If this is a CALL_INSN and its delay slots, it is hard to track ! 1629: the resource needs properly, so give up. */ ! 1630: if (GET_CODE (XVECEXP (pat, 0, 0)) == CALL_INSN) ! 1631: return 0; ! 1632: ! 1633: /* See if any of the insns in the delay slot match, updating ! 1634: resource requirements as we go. */ ! 1635: for (i = XVECLEN (pat, 0) - 1; i > 0; i--) ! 1636: { ! 1637: rtx candidate = XVECEXP (pat, 0, i); ! 1638: ! 1639: /* If an insn will be annulled if the branch is false, it isn't ! 1640: considered as a possible duplicate insn. */ ! 1641: if (rtx_equal_p (PATTERN (candidate), ipat) ! 1642: && ! (INSN_ANNULLED_BRANCH_P (XVECEXP (pat, 0, 0)) ! 1643: && INSN_FROM_TARGET_P (candidate))) ! 1644: { ! 1645: /* Show that this insn will be used in the sequel. */ ! 1646: INSN_FROM_TARGET_P (candidate) = 0; ! 1647: return 1; ! 1648: } ! 1649: ! 1650: /* Unless this is an annulled insn from the target of a branch, ! 1651: we must stop if it sets anything needed or set by INSN. */ ! 1652: if ((! INSN_ANNULLED_BRANCH_P (XVECEXP (pat, 0, 0)) ! 1653: || ! INSN_FROM_TARGET_P (candidate)) ! 1654: && insn_sets_resource_p (candidate, &needed, 1)) ! 1655: return 0; ! 1656: } ! 1657: ! 1658: ! 1659: /* If the insn requiring the delay slot conflicts with INSN, we ! 1660: must stop. */ ! 1661: if (insn_sets_resource_p (XVECEXP (pat, 0, 0), &needed, 1)) ! 1662: return 0; ! 1663: } ! 1664: else ! 1665: { ! 1666: /* See if TRIAL is the same as INSN. */ ! 1667: pat = PATTERN (trial); ! 1668: if (rtx_equal_p (pat, ipat)) ! 1669: return 1; ! 1670: ! 1671: /* Can't go any further if TRIAL conflicts with INSN. */ ! 1672: if (insn_sets_resource_p (trial, &needed, 1)) ! 1673: return 0; ! 1674: } ! 1675: } ! 1676: ! 1677: return 0; ! 1678: } ! 1679: ! 1680: /* Return 1 if THREAD can only be executed in one way. If LABEL is non-zero, ! 1681: it is the target of the branch insn being scanned. If ALLOW_FALLTHROUGH ! 1682: is non-zero, we are allowed to fall into this thread; otherwise, we are ! 1683: not. ! 1684: ! 1685: If LABEL is used more than one or we pass a label other than LABEL before ! 1686: finding an active insn, we do not own this thread. */ ! 1687: ! 1688: static int ! 1689: own_thread_p (thread, label, allow_fallthrough) ! 1690: rtx thread; ! 1691: rtx label; ! 1692: int allow_fallthrough; ! 1693: { ! 1694: rtx active_insn; ! 1695: rtx insn; ! 1696: ! 1697: /* We don't own the function end. */ ! 1698: if (thread == 0) ! 1699: return 0; ! 1700: ! 1701: /* Get the first active insn, or THREAD, if it is an active insn. */ ! 1702: active_insn = next_active_insn (PREV_INSN (thread)); ! 1703: ! 1704: for (insn = thread; insn != active_insn; insn = NEXT_INSN (insn)) ! 1705: if (GET_CODE (insn) == CODE_LABEL ! 1706: && (insn != label || LABEL_NUSES (insn) != 1)) ! 1707: return 0; ! 1708: ! 1709: if (allow_fallthrough) ! 1710: return 1; ! 1711: ! 1712: /* Ensure that we reach a BARRIER before any insn or label. */ ! 1713: for (insn = prev_nonnote_insn (thread); ! 1714: insn == 0 || GET_CODE (insn) != BARRIER; ! 1715: insn = prev_nonnote_insn (insn)) ! 1716: if (insn == 0 ! 1717: || GET_CODE (insn) == CODE_LABEL ! 1718: || (GET_CODE (insn) == INSN ! 1719: && GET_CODE (PATTERN (insn)) != USE ! 1720: && GET_CODE (PATTERN (insn)) != CLOBBER)) ! 1721: return 0; ! 1722: ! 1723: return 1; ! 1724: } ! 1725: ! 1726: /* Find the number of the basic block that starts closest to INSN. Return -1 ! 1727: if we couldn't find such a basic block. */ ! 1728: ! 1729: static int ! 1730: find_basic_block (insn) ! 1731: rtx insn; ! 1732: { ! 1733: int i; ! 1734: ! 1735: /* Scan backwards to the previous BARRIER. Then see if we can find a ! 1736: label that starts a basic block. Return the basic block number. */ ! 1737: ! 1738: for (insn = prev_nonnote_insn (insn); ! 1739: insn && GET_CODE (insn) != BARRIER; ! 1740: insn = prev_nonnote_insn (insn)) ! 1741: ; ! 1742: ! 1743: /* The start of the function is basic block zero. */ ! 1744: if (insn == 0) ! 1745: return 0; ! 1746: ! 1747: /* See if any of the upcoming CODE_LABELs start a basic block. If we reach ! 1748: anything other than a CODE_LABEL or note, we can't find this code. */ ! 1749: for (insn = next_nonnote_insn (insn); ! 1750: insn && GET_CODE (insn) == CODE_LABEL; ! 1751: insn = next_nonnote_insn (insn)) ! 1752: { ! 1753: for (i = 0; i < n_basic_blocks; i++) ! 1754: if (insn == basic_block_head[i]) ! 1755: return i; ! 1756: } ! 1757: ! 1758: return -1; ! 1759: } ! 1760: ! 1761: /* Used for communication between the following two routines, contains ! 1762: the block number that insn was in. */ ! 1763: ! 1764: static int current_block_number; ! 1765: ! 1766: /* Called via note_stores from update_block_status. It marks the ! 1767: registers set in this insn as live at the start of the block whose ! 1768: number is in current_block_number. */ ! 1769: ! 1770: static void ! 1771: update_block_from_store (dest, x) ! 1772: rtx dest; ! 1773: rtx x; ! 1774: { ! 1775: int first_regno, last_regno; ! 1776: int offset = 0; ! 1777: int i; ! 1778: ! 1779: if (GET_CODE (x) != SET ! 1780: || (GET_CODE (dest) != REG && (GET_CODE (dest) != SUBREG ! 1781: || GET_CODE (SUBREG_REG (dest)) != REG))) ! 1782: return; ! 1783: ! 1784: if (GET_CODE (dest) == SUBREG) ! 1785: first_regno = REGNO (SUBREG_REG (dest)) + SUBREG_WORD (dest); ! 1786: else ! 1787: first_regno = REGNO (dest); ! 1788: ! 1789: last_regno = first_regno + HARD_REGNO_NREGS (first_regno, GET_MODE (dest)); ! 1790: for (i = first_regno; i < last_regno; i++) ! 1791: basic_block_live_at_start[current_block_number][i / HOST_BITS_PER_INT] ! 1792: |= (1 << (i % HOST_BITS_PER_INT)); ! 1793: } ! 1794: ! 1795: /* Called when INSN is being moved from a location near the target of a jump. ! 1796: If WHERE is the first active insn at the start of its basic block, we can ! 1797: just mark the registers set in INSN as live at the start of the basic block ! 1798: that starts immediately before INSN. ! 1799: ! 1800: Otherwise, we leave a marker of the form (use (INSN)) immediately in front ! 1801: of WHERE for mark_target_live_regs. These markers will be deleted when ! 1802: reorg finishes. */ ! 1803: ! 1804: static void ! 1805: update_block (insn, where) ! 1806: rtx insn; ! 1807: rtx where; ! 1808: { ! 1809: /* Ignore if this was in a delay slot and it came from the target of ! 1810: a branch. */ ! 1811: if (INSN_FROM_TARGET_P (insn)) ! 1812: return; ! 1813: ! 1814: current_block_number = find_basic_block (insn); ! 1815: if (current_block_number == -1) ! 1816: return; ! 1817: ! 1818: if (where == next_active_insn (basic_block_head[current_block_number])) ! 1819: note_stores (PATTERN (insn), update_block_from_store); ! 1820: else ! 1821: emit_insn_before (gen_rtx (USE, VOIDmode, insn), where); ! 1822: ! 1823: /* INSN might be making a value live in a block where it didn't use to ! 1824: be. So recompute liveness information for this block. */ ! 1825: bb_ticks[current_block_number]++; ! 1826: } ! 1827: ! 1828: /* Marks registers possibly live at the current place being scanned by ! 1829: mark_target_live_regs. Used only by next two function. */ ! 1830: ! 1831: static HARD_REG_SET current_live_regs; ! 1832: ! 1833: /* Marks registers for which we have seen a REG_DEAD note but no assignment. ! 1834: Also only used by the next two functions. */ ! 1835: ! 1836: static HARD_REG_SET pending_dead_regs; ! 1837: ! 1838: /* Utility function called from mark_target_live_regs via note_stores. ! 1839: It deadens any CLOBBERed registers and livens any SET registers. */ ! 1840: ! 1841: static void ! 1842: update_live_status (dest, x) ! 1843: rtx dest; ! 1844: rtx x; ! 1845: { ! 1846: int first_regno, last_regno; ! 1847: int i; ! 1848: ! 1849: if (GET_CODE (dest) != REG ! 1850: && (GET_CODE (dest) != SUBREG || GET_CODE (SUBREG_REG (dest)) != REG)) ! 1851: return; ! 1852: ! 1853: if (GET_CODE (dest) == SUBREG) ! 1854: first_regno = REGNO (SUBREG_REG (dest)) + SUBREG_WORD (dest); ! 1855: else ! 1856: first_regno = REGNO (dest); ! 1857: ! 1858: last_regno = first_regno + HARD_REGNO_NREGS (first_regno, GET_MODE (dest)); ! 1859: ! 1860: if (GET_CODE (x) == CLOBBER) ! 1861: for (i = first_regno; i < last_regno; i++) ! 1862: CLEAR_HARD_REG_BIT (current_live_regs, i); ! 1863: else ! 1864: for (i = first_regno; i < last_regno; i++) ! 1865: { ! 1866: SET_HARD_REG_BIT (current_live_regs, i); ! 1867: CLEAR_HARD_REG_BIT (pending_dead_regs, i); ! 1868: } ! 1869: } ! 1870: ! 1871: /* Similar to next_insn, but ignores insns in the delay slots of ! 1872: an annulled branch. */ ! 1873: ! 1874: static rtx ! 1875: next_insn_no_annul (insn) ! 1876: rtx insn; ! 1877: { ! 1878: if (insn) ! 1879: { ! 1880: /* If INSN is an annulled branch, skip any insns from the target ! 1881: of the branch. */ ! 1882: if (INSN_ANNULLED_BRANCH_P (insn) ! 1883: && NEXT_INSN (PREV_INSN (insn)) != insn) ! 1884: while (INSN_FROM_TARGET_P (NEXT_INSN (insn))) ! 1885: insn = NEXT_INSN (insn); ! 1886: ! 1887: insn = NEXT_INSN (insn); ! 1888: if (insn && GET_CODE (insn) == INSN ! 1889: && GET_CODE (PATTERN (insn)) == SEQUENCE) ! 1890: insn = XVECEXP (PATTERN (insn), 0, 0); ! 1891: } ! 1892: ! 1893: return insn; ! 1894: } ! 1895: ! 1896: /* Set the resources that are live at TARGET. ! 1897: ! 1898: If TARGET is zero, we refer to the end of the current function and can ! 1899: return our precomputed value. ! 1900: ! 1901: Otherwise, we try to find out what is live by consulting the basic block ! 1902: information. This is tricky, because we must consider the actions of ! 1903: reload and jump optimization, which occur after the basic block information ! 1904: has been computed. ! 1905: ! 1906: Accordingly, we proceed as follows:: ! 1907: ! 1908: We find the previous BARRIER and look at all immediately following labels ! 1909: (with no intervening active insns) to see if any of them start a basic ! 1910: block. If we hit the start of the function first, we use block 0. ! 1911: ! 1912: Once we have found a basic block and a corresponding first insns, we can ! 1913: accurately compute the live status from basic_block_live_regs and ! 1914: reg_renumber. (By starting at a label following a BARRIER, we are immune ! 1915: to actions taken by reload and jump.) Then we scan all insns between ! 1916: that point and our target. For each CLOBBER (or for call-clobbered regs ! 1917: when we pass a CALL_INSN), mark the appropriate registers are dead. For ! 1918: a SET, mark them as live. ! 1919: ! 1920: We have to be careful when using REG_DEAD notes because they are not ! 1921: updated by such things as find_equiv_reg. So keep track of registers ! 1922: marked as dead that haven't been assigned to, and mark them dead at the ! 1923: next CODE_LABEL since reload and jump won't propagate values across labels. ! 1924: ! 1925: If we cannot find the start of a basic block (should be a very rare ! 1926: case, if it can happen at all), mark everything as potentially live. ! 1927: ! 1928: Next, scan forward from TARGET looking for things set or clobbered ! 1929: before they are used. These are not live. ! 1930: ! 1931: Because we can be called many times on the same target, save our results ! 1932: in a hash table indexed by INSN_UID. */ ! 1933: ! 1934: static void ! 1935: mark_target_live_regs (target, res) ! 1936: rtx target; ! 1937: struct resources *res; ! 1938: { ! 1939: int b = -1; ! 1940: int i; ! 1941: struct target_info *tinfo; ! 1942: rtx insn, next; ! 1943: rtx jump_insn = 0; ! 1944: HARD_REG_SET scratch; ! 1945: struct resources set, needed; ! 1946: int jump_count = 0; ! 1947: ! 1948: /* Handle end of function. */ ! 1949: if (target == 0) ! 1950: { ! 1951: *res = end_of_function_needs; ! 1952: return; ! 1953: } ! 1954: ! 1955: /* We have to assume memory is needed, but the CC isn't. */ ! 1956: res->memory = 1; ! 1957: res->volatil = 0; ! 1958: res->cc = 0; ! 1959: ! 1960: /* See if we have computed this value already. */ ! 1961: for (tinfo = target_hash_table[INSN_UID (target) % TARGET_HASH_PRIME]; ! 1962: tinfo; tinfo = tinfo->next) ! 1963: if (tinfo->uid == INSN_UID (target)) ! 1964: break; ! 1965: ! 1966: /* Start by getting the basic block number. If we have saved information, ! 1967: we can get it from there unless the insn at the start of the basic block ! 1968: has been deleted. */ ! 1969: if (tinfo && tinfo->block != -1 ! 1970: && ! INSN_DELETED_P (basic_block_head[tinfo->block])) ! 1971: b = tinfo->block; ! 1972: ! 1973: if (b == -1) ! 1974: b = find_basic_block (target); ! 1975: ! 1976: if (tinfo) ! 1977: { ! 1978: /* If the information is up-to-date, use it. Otherwise, we will ! 1979: update it below. */ ! 1980: if (b == tinfo->block && b != -1 && tinfo->bb_tick == bb_ticks[b]) ! 1981: { ! 1982: COPY_HARD_REG_SET (res->regs, tinfo->live_regs); ! 1983: return; ! 1984: } ! 1985: } ! 1986: else ! 1987: { ! 1988: /* Allocate a place to put our results and chain it into the ! 1989: hash table. */ ! 1990: tinfo = (struct target_info *) oballoc (sizeof (struct target_info)); ! 1991: tinfo->uid = INSN_UID (target); ! 1992: tinfo->block = b; ! 1993: tinfo->next = target_hash_table[INSN_UID (target) % TARGET_HASH_PRIME]; ! 1994: target_hash_table[INSN_UID (target) % TARGET_HASH_PRIME] = tinfo; ! 1995: } ! 1996: ! 1997: CLEAR_HARD_REG_SET (pending_dead_regs); ! 1998: ! 1999: /* If we found a basic block, get the live registers from it and update ! 2000: them with anything set or killed between its start and the insn before ! 2001: TARGET. Otherwise, we must assume everything is live. */ ! 2002: if (b != -1) ! 2003: { ! 2004: regset regs_live = basic_block_live_at_start[b]; ! 2005: int offset, bit, j; ! 2006: int regno; ! 2007: rtx start_insn, stop_insn; ! 2008: ! 2009: /* Compute hard regs live at start of block -- this is the real hard regs ! 2010: marked live, plus live pseudo regs that have been renumbered to ! 2011: hard regs. */ ! 2012: ! 2013: #ifdef HARD_REG_SET ! 2014: current_live_regs = *regs_live; ! 2015: #else ! 2016: COPY_HARD_REG_SET (current_live_regs, regs_live); ! 2017: #endif ! 2018: ! 2019: for (offset = 0, i = 0; offset < regset_size; offset++) ! 2020: { ! 2021: if (regs_live[offset] == 0) ! 2022: i += HOST_BITS_PER_INT; ! 2023: else ! 2024: for (bit = 1; bit && i < max_regno; bit <<= 1, i++) ! 2025: if ((regs_live[offset] & bit) ! 2026: && (regno = reg_renumber[i]) >= 0) ! 2027: for (j = regno; ! 2028: j < regno + HARD_REGNO_NREGS (regno, ! 2029: PSEUDO_REGNO_MODE (i)); ! 2030: j++) ! 2031: SET_HARD_REG_BIT (current_live_regs, j); ! 2032: } ! 2033: ! 2034: /* Get starting and ending insn, handling the case where each might ! 2035: be a SEQUENCE. */ ! 2036: start_insn = (b == 0 ? get_insns () : basic_block_head[b]); ! 2037: stop_insn = target; ! 2038: ! 2039: if (GET_CODE (start_insn) == INSN ! 2040: && GET_CODE (PATTERN (start_insn)) == SEQUENCE) ! 2041: start_insn = XVECEXP (PATTERN (start_insn), 0, 0); ! 2042: ! 2043: if (GET_CODE (stop_insn) == INSN ! 2044: && GET_CODE (PATTERN (stop_insn)) == SEQUENCE) ! 2045: stop_insn = next_insn (PREV_INSN (stop_insn)); ! 2046: ! 2047: for (insn = start_insn; insn != stop_insn; ! 2048: insn = next_insn_no_annul (insn)) ! 2049: { ! 2050: rtx link; ! 2051: rtx real_insn = insn; ! 2052: ! 2053: /* If this insn is from the target of a branch, it isn't going to ! 2054: be used in the sequel. If it is used in both cases, this ! 2055: test will not be true. */ ! 2056: if (INSN_FROM_TARGET_P (insn)) ! 2057: continue; ! 2058: ! 2059: /* If this insn is a USE made by update_block, we care about the ! 2060: underlying insn. */ ! 2061: if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == USE ! 2062: && (GET_CODE (XEXP (PATTERN (insn), 0)) == INSN ! 2063: || GET_CODE (XEXP (PATTERN (insn), 0)) == CALL_INSN ! 2064: || GET_CODE (XEXP (PATTERN (insn), 0)) == JUMP_INSN)) ! 2065: real_insn = XEXP (PATTERN (insn), 0); ! 2066: ! 2067: if (GET_CODE (real_insn) == CALL_INSN) ! 2068: { ! 2069: /* CALL clobbers all call-used regs that aren't fixed except ! 2070: sp, ap, and fp. Do this before setting the result of the ! 2071: call live. */ ! 2072: for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) ! 2073: if (call_used_regs[i] ! 2074: && i != STACK_POINTER_REGNUM && i != FRAME_POINTER_REGNUM ! 2075: && i != ARG_POINTER_REGNUM ! 2076: #if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM ! 2077: && ! (i == ARG_POINTER_REGNUM && fixed_regs[i]) ! 2078: #endif ! 2079: #ifdef PIC_OFFSET_TABLE_REGNUM ! 2080: && ! (i == PIC_OFFSET_TABLE_REGNUM && flag_pic) ! 2081: #endif ! 2082: ) ! 2083: CLEAR_HARD_REG_BIT (current_live_regs, i); ! 2084: } ! 2085: ! 2086: /* Mark anything killed in an insn to be deadened at the next ! 2087: label. Ignore USE insns; the only REG_DEAD notes will be for ! 2088: parameters. But they might be early. A CALL_INSN will usually ! 2089: clobber registers used for parameters. It isn't worth bothering ! 2090: with the unlikely case when it won't. */ ! 2091: if ((GET_CODE (real_insn) == INSN ! 2092: && GET_CODE (PATTERN (real_insn)) != USE) ! 2093: || GET_CODE (real_insn) == JUMP_INSN ! 2094: || GET_CODE (real_insn) == CALL_INSN) ! 2095: { ! 2096: for (link = REG_NOTES (real_insn); link; link = XEXP (link, 1)) ! 2097: if (REG_NOTE_KIND (link) == REG_DEAD ! 2098: && GET_CODE (XEXP (link, 0)) == REG ! 2099: && REGNO (XEXP (link, 0)) < FIRST_PSEUDO_REGISTER) ! 2100: { ! 2101: int first_regno = REGNO (XEXP (link, 0)); ! 2102: int last_regno ! 2103: = (first_regno ! 2104: + HARD_REGNO_NREGS (first_regno, ! 2105: GET_MODE (XEXP (link, 0)))); ! 2106: ! 2107: for (i = first_regno; i < last_regno; i++) ! 2108: SET_HARD_REG_BIT (pending_dead_regs, i); ! 2109: } ! 2110: ! 2111: note_stores (PATTERN (real_insn), update_live_status); ! 2112: ! 2113: /* If any registers were unused after this insn, kill them. ! 2114: These notes will always be accurate. */ ! 2115: for (link = REG_NOTES (real_insn); link; link = XEXP (link, 1)) ! 2116: if (REG_NOTE_KIND (link) == REG_UNUSED ! 2117: && GET_CODE (XEXP (link, 0)) == REG ! 2118: && REGNO (XEXP (link, 0)) < FIRST_PSEUDO_REGISTER) ! 2119: { ! 2120: int first_regno = REGNO (XEXP (link, 0)); ! 2121: int last_regno ! 2122: = (first_regno ! 2123: + HARD_REGNO_NREGS (first_regno, ! 2124: GET_MODE (XEXP (link, 0)))); ! 2125: ! 2126: for (i = first_regno; i < last_regno; i++) ! 2127: CLEAR_HARD_REG_BIT (current_live_regs, i); ! 2128: } ! 2129: } ! 2130: ! 2131: if (GET_CODE (real_insn) == CODE_LABEL) ! 2132: { ! 2133: /* A label clobbers the pending dead registers since neither ! 2134: reload nor jump will propagate a value across a label. */ ! 2135: AND_COMPL_HARD_REG_SET (current_live_regs, pending_dead_regs); ! 2136: CLEAR_HARD_REG_SET (pending_dead_regs); ! 2137: } ! 2138: } ! 2139: ! 2140: COPY_HARD_REG_SET (res->regs, current_live_regs); ! 2141: tinfo->block = b; ! 2142: tinfo->bb_tick = bb_ticks[b]; ! 2143: } ! 2144: else ! 2145: /* We didn't find the start of a basic block. Assume everything ! 2146: in use. This should happen only extremely rarely. */ ! 2147: SET_HARD_REG_SET (res->regs); ! 2148: ! 2149: /* Now step forward from TARGET looking for registers that are set before ! 2150: they are used. These are dead. If we pass a label, any pending dead ! 2151: registers that weren't yet used can be made dead. Stop when we pass a ! 2152: conditional JUMP_INSN; follow the first few unconditional branches. */ ! 2153: ! 2154: CLEAR_RESOURCE (&set); ! 2155: CLEAR_RESOURCE (&needed); ! 2156: ! 2157: for (insn = target; insn; insn = next) ! 2158: { ! 2159: rtx main_insn = insn; ! 2160: ! 2161: next = NEXT_INSN (insn); ! 2162: switch (GET_CODE (insn)) ! 2163: { ! 2164: case CODE_LABEL: ! 2165: AND_COMPL_HARD_REG_SET (pending_dead_regs, needed.regs); ! 2166: AND_COMPL_HARD_REG_SET (res->regs, pending_dead_regs); ! 2167: CLEAR_HARD_REG_SET (pending_dead_regs); ! 2168: continue; ! 2169: ! 2170: case BARRIER: ! 2171: case NOTE: ! 2172: continue; ! 2173: ! 2174: case INSN: ! 2175: if (GET_CODE (PATTERN (insn)) == USE ! 2176: || GET_CODE (PATTERN (insn)) == CLOBBER) ! 2177: continue; ! 2178: if (GET_CODE (PATTERN (insn)) == SEQUENCE) ! 2179: main_insn = XVECEXP (PATTERN (insn), 0, 0); ! 2180: } ! 2181: ! 2182: if (GET_CODE (main_insn) == JUMP_INSN) ! 2183: { ! 2184: if (jump_count++ < 10 ! 2185: && (simplejump_p (main_insn) ! 2186: || GET_CODE (PATTERN (main_insn)) == RETURN)) ! 2187: { ! 2188: next = next_active_insn (JUMP_LABEL (main_insn)); ! 2189: if (jump_insn == 0) ! 2190: jump_insn = insn; ! 2191: } ! 2192: else ! 2193: break; ! 2194: } ! 2195: ! 2196: mark_referenced_resources (insn, &needed, 1); ! 2197: mark_set_resources (insn, &set, 1); ! 2198: ! 2199: COPY_HARD_REG_SET (scratch, set.regs); ! 2200: AND_COMPL_HARD_REG_SET (scratch, needed.regs); ! 2201: AND_COMPL_HARD_REG_SET (res->regs, scratch); ! 2202: } ! 2203: ! 2204: /* If we hit an unconditional branch, we have another way of finding out ! 2205: what is live: we can see what is live at the branch target and include ! 2206: anything used but not set before the branch. The only things that are ! 2207: live are those that are live using the above test and the test below. */ ! 2208: if (jump_insn) ! 2209: { ! 2210: rtx jump_target = (GET_CODE (jump_insn) == INSN ! 2211: ? JUMP_LABEL (XVECEXP (PATTERN (jump_insn), 0, 0)) ! 2212: : JUMP_LABEL (jump_insn)); ! 2213: struct resources new_resources; ! 2214: rtx stop_insn = next_active_insn (jump_insn); ! 2215: ! 2216: mark_target_live_regs (next_active_insn (jump_target), &new_resources); ! 2217: CLEAR_RESOURCE (&set); ! 2218: CLEAR_RESOURCE (&needed); ! 2219: ! 2220: /* Include JUMP_INSN in the needed registers. */ ! 2221: for (insn = target; insn != stop_insn; insn = next_active_insn (insn)) ! 2222: { ! 2223: mark_referenced_resources (insn, &needed, 1); ! 2224: ! 2225: COPY_HARD_REG_SET (scratch, needed.regs); ! 2226: AND_COMPL_HARD_REG_SET (scratch, set.regs); ! 2227: IOR_HARD_REG_SET (new_resources.regs, scratch); ! 2228: ! 2229: mark_set_resources (insn, &set, 1); ! 2230: } ! 2231: ! 2232: AND_HARD_REG_SET (res->regs, new_resources.regs); ! 2233: } ! 2234: ! 2235: COPY_HARD_REG_SET (tinfo->live_regs, res->regs); ! 2236: } ! 2237: ! 2238: /* Scan a function looking for insns that need a delay slot and find insns to ! 2239: put into the delay slot. ! 2240: ! 2241: NON_JUMPS_P is non-zero if we are to only try to fill non-jump insns (such ! 2242: as calls). We do these first since we don't want jump insns (that are ! 2243: easier to fill) to get the only insns that could be used for non-jump insns. ! 2244: When it is zero, only try to fill JUMP_INSNs. ! 2245: ! 2246: When slots are filled in this manner, the insns (including the ! 2247: delay_insn) are put together in a SEQUENCE rtx. In this fashion, ! 2248: it is possible to tell whether a delay slot has really been filled ! 2249: or not. `final' knows how to deal with this, by communicating ! 2250: through FINAL_SEQUENCE. */ ! 2251: ! 2252: static void ! 2253: fill_simple_delay_slots (first, non_jumps_p) ! 2254: rtx first; ! 2255: { ! 2256: register rtx insn, pat, trial, next_trial; ! 2257: register int i; ! 2258: int num_unfilled_slots = unfilled_slots_next - unfilled_slots_base; ! 2259: struct resources needed, set; ! 2260: register int slots_to_fill, slots_filled; ! 2261: rtx delay_list; ! 2262: ! 2263: for (i = 0; i < num_unfilled_slots; i++) ! 2264: { ! 2265: /* Get the next insn to fill. If it has already had any slots assigned, ! 2266: we can't do anything with it. Maybe we'll improve this later. */ ! 2267: ! 2268: insn = unfilled_slots_base[i]; ! 2269: if (insn == 0 ! 2270: || INSN_DELETED_P (insn) ! 2271: || (GET_CODE (insn) == INSN ! 2272: && GET_CODE (PATTERN (insn)) == SEQUENCE) ! 2273: || (GET_CODE (insn) == JUMP_INSN && non_jumps_p) ! 2274: || (GET_CODE (insn) != JUMP_INSN && ! non_jumps_p)) ! 2275: continue; ! 2276: ! 2277: slots_to_fill = num_delay_slots (insn); ! 2278: if (slots_to_fill == 0) ! 2279: abort (); ! 2280: ! 2281: /* This insn needs, or can use, some delay slots. SLOTS_TO_FILL ! 2282: says how many. After initialization, scan backwards from the ! 2283: insn to search for a potential delay-slot candidate. Stop ! 2284: searching when a label or jump is hit. ! 2285: ! 2286: For each candidate, if it is to go into the delay slot (moved ! 2287: forward in execution sequence), it must not need or set any resources ! 2288: that were set by later insns and must not set any resources that ! 2289: are needed for those insns. ! 2290: ! 2291: The delay slot insn itself sets resources unless it is a call ! 2292: (in which case the called routine, not the insn itself, is doing ! 2293: the setting). */ ! 2294: ! 2295: slots_filled = 0; ! 2296: delay_list = 0; ! 2297: CLEAR_RESOURCE (&needed); ! 2298: CLEAR_RESOURCE (&set); ! 2299: mark_set_resources (insn, &set, 0); ! 2300: mark_referenced_resources (insn, &needed, 0); ! 2301: ! 2302: for (trial = prev_nonnote_insn (insn); ! stop_search_p (trial, 1); ! 2303: trial = next_trial) ! 2304: { ! 2305: next_trial = prev_nonnote_insn (trial); ! 2306: ! 2307: /* This must be an INSN or CALL_INSN. */ ! 2308: pat = PATTERN (trial); ! 2309: ! 2310: /* USE and CLOBBER at this level was just for flow; ignore it. */ ! 2311: if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER) ! 2312: continue; ! 2313: ! 2314: /* Check for resource conflict first, to avoid unnecessary ! 2315: splitting. */ ! 2316: if (! insn_references_resource_p (trial, &set, 1) ! 2317: && ! insn_sets_resource_p (trial, &set, 1) ! 2318: && ! insn_sets_resource_p (trial, &needed, 1) ! 2319: #ifdef HAVE_cc0 ! 2320: /* Can't separate set of cc0 from its use. */ ! 2321: && ! (reg_mentioned_p (cc0_rtx, pat) ! 2322: && ! sets_cc0_p (cc0_rtx, pat)) ! 2323: #endif ! 2324: ) ! 2325: { ! 2326: trial = try_split (pat, trial, 1); ! 2327: next_trial = prev_nonnote_insn (trial); ! 2328: if (eligible_for_delay (insn, slots_filled, trial)) ! 2329: { ! 2330: /* In this case, we are searching backward, so if we ! 2331: find insns to put on the delay list, we want ! 2332: to put them at the head, rather than the ! 2333: tail, of the list. */ ! 2334: ! 2335: delay_list = gen_rtx (INSN_LIST, VOIDmode, ! 2336: trial, delay_list); ! 2337: update_block (trial, trial); ! 2338: delete_insn (trial); ! 2339: if (slots_to_fill == ++slots_filled) ! 2340: break; ! 2341: continue; ! 2342: } ! 2343: } ! 2344: ! 2345: mark_set_resources (trial, &set, 1); ! 2346: mark_referenced_resources (trial, &needed, 1); ! 2347: } ! 2348: ! 2349: if (slots_filled == slots_to_fill) ! 2350: /* happy. */ ; ! 2351: ! 2352: /* If all needed slots haven't been filled, we come here. */ ! 2353: ! 2354: /* Try to optimize case of jumping around a single insn. */ ! 2355: #if defined(ANNUL_IFFALSE_SLOTS) || defined(ANNUL_IFTRUE_SLOTS) ! 2356: else if (delay_list == 0 ! 2357: && GET_CODE (insn) == JUMP_INSN && condjump_p (insn)) ! 2358: { ! 2359: delay_list = optimize_skip (insn); ! 2360: if (delay_list) ! 2361: slots_filled += 1; ! 2362: } ! 2363: #endif ! 2364: ! 2365: /* @@ This would be a good place to optimize: ! 2366: ! 2367: call _foo call _foo ! 2368: nop add %o7,.-L1,%o7 ! 2369: b,a L1 ! 2370: nop ! 2371: ! 2372: Someday... */ ! 2373: ! 2374: /* Try to get insns from beyond the insn needing the delay slot. ! 2375: These insns can neither set or reference resources set in insns being ! 2376: skipped, cannot set resources in the insn being skipped, and, if this ! 2377: is a CALL_INSN (or a CALL_INSN is passed), cannot trap (because the ! 2378: call might not return). ! 2379: ! 2380: If this is a conditional jump, see if it merges back to us early ! 2381: enough for us to pick up insns from the merge point. Don't do ! 2382: this if there is another branch to our label unless we pass all of ! 2383: them. ! 2384: ! 2385: Another similar merge is if we jump to the same place that a ! 2386: later unconditional jump branches to. In that case, we don't ! 2387: care about the number of uses of our label. */ ! 2388: ! 2389: else if (GET_CODE (insn) != JUMP_INSN ! 2390: || (condjump_p (insn) && ! simplejump_p (insn) ! 2391: && JUMP_LABEL (insn) != 0)) ! 2392: { ! 2393: rtx target = 0; ! 2394: int maybe_never = 0; ! 2395: int passed_label = 0; ! 2396: int target_uses; ! 2397: struct resources needed_at_jump; ! 2398: ! 2399: CLEAR_RESOURCE (&needed); ! 2400: CLEAR_RESOURCE (&set); ! 2401: ! 2402: if (GET_CODE (insn) == CALL_INSN) ! 2403: { ! 2404: mark_set_resources (insn, &set, 1); ! 2405: mark_referenced_resources (insn, &needed, 1); ! 2406: maybe_never = 1; ! 2407: } ! 2408: else if (GET_CODE (insn) == JUMP_INSN) ! 2409: { ! 2410: /* Get our target and show how many more uses we want to ! 2411: see before we hit the label. */ ! 2412: target = JUMP_LABEL (insn); ! 2413: target_uses = LABEL_NUSES (target) - 1; ! 2414: } ! 2415: ! 2416: for (trial = next_nonnote_insn (insn); trial; trial = next_trial) ! 2417: { ! 2418: rtx pat, trial_delay; ! 2419: ! 2420: next_trial = next_nonnote_insn (trial); ! 2421: ! 2422: if (GET_CODE (trial) == CODE_LABEL) ! 2423: { ! 2424: passed_label = 1; ! 2425: ! 2426: /* If this is our target, see if we have seen all its uses. ! 2427: If so, indicate we have passed our target and ignore it. ! 2428: All other labels cause us to stop our search. */ ! 2429: if (trial == target && target_uses == 0) ! 2430: { ! 2431: target = 0; ! 2432: continue; ! 2433: } ! 2434: else ! 2435: break; ! 2436: } ! 2437: else if (GET_CODE (trial) == BARRIER) ! 2438: break; ! 2439: ! 2440: /* We must have an INSN, JUMP_INSN, or CALL_INSN. */ ! 2441: pat = PATTERN (trial); ! 2442: ! 2443: /* Stand-alone USE and CLOBBER are just for flow. */ ! 2444: if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER) ! 2445: continue; ! 2446: ! 2447: /* If this already has filled delay slots, get the insn needing ! 2448: the delay slots. */ ! 2449: if (GET_CODE (pat) == SEQUENCE) ! 2450: trial_delay = XVECEXP (pat, 0, 0); ! 2451: else ! 2452: trial_delay = trial; ! 2453: ! 2454: /* If this is a jump insn to our target, indicate that we have ! 2455: seen another jump to it. If we aren't handling a conditional ! 2456: jump, stop our search. Otherwise, compute the needs at its ! 2457: target and add them to NEEDED. */ ! 2458: if (GET_CODE (trial_delay) == JUMP_INSN) ! 2459: { ! 2460: if (target == 0) ! 2461: break; ! 2462: else if (JUMP_LABEL (trial_delay) == target) ! 2463: target_uses--; ! 2464: else ! 2465: { ! 2466: mark_target_live_regs ! 2467: (next_active_insn (JUMP_LABEL (trial_delay)), ! 2468: &needed_at_jump); ! 2469: needed.memory |= needed_at_jump.memory; ! 2470: IOR_HARD_REG_SET (needed.regs, needed_at_jump.regs); ! 2471: } ! 2472: } ! 2473: ! 2474: /* See if we have a resource problem before we try to ! 2475: split. */ ! 2476: if (target == 0 ! 2477: && GET_CODE (pat) != SEQUENCE ! 2478: && ! insn_references_resource_p (trial, &set, 1) ! 2479: && ! insn_sets_resource_p (trial, &set, 1) ! 2480: && ! insn_sets_resource_p (trial, &needed, 1) ! 2481: #ifdef HAVE_cc0 ! 2482: && ! (reg_mentioned_p (cc0_rtx, pat) && ! sets_cc0_p (pat)) ! 2483: #endif ! 2484: && ! (maybe_never && may_trap_p (pat)) ! 2485: && (trial = try_split (pat, trial, 0)) ! 2486: && eligible_for_delay (insn, slots_filled, trial)) ! 2487: { ! 2488: next_trial = next_nonnote_insn (trial); ! 2489: delay_list = add_to_delay_list (trial, delay_list); ! 2490: ! 2491: #ifdef HAVE_cc0 ! 2492: if (reg_mentioned_p (cc0_rtx, pat)) ! 2493: link_cc0_insns (trial); ! 2494: #endif ! 2495: ! 2496: if (passed_label) ! 2497: update_block (trial, trial); ! 2498: delete_insn (trial); ! 2499: if (slots_to_fill == ++slots_filled) ! 2500: break; ! 2501: continue; ! 2502: } ! 2503: ! 2504: mark_set_resources (trial, &set, 1); ! 2505: mark_referenced_resources (trial, &needed, 1); ! 2506: ! 2507: /* Ensure we don't put insns between the setting of cc and the ! 2508: comparison by moving a setting of cc into an earlier delay ! 2509: slot since these insns could clobber the condition code. */ ! 2510: set.cc = 1; ! 2511: ! 2512: /* If this is a call or jump, we might not get here. */ ! 2513: if (GET_CODE (trial) == CALL_INSN ! 2514: || GET_CODE (trial) == JUMP_INSN) ! 2515: maybe_never = 1; ! 2516: } ! 2517: ! 2518: /* If there are slots left to fill and our search was stopped by an ! 2519: unconditional branch, try the insn at the branch target. We can ! 2520: redirect the branch if it works. */ ! 2521: if (slots_to_fill != slots_filled ! 2522: && trial ! 2523: && GET_CODE (trial) == JUMP_INSN ! 2524: && simplejump_p (trial) ! 2525: && (target == 0 || JUMP_LABEL (trial) == target) ! 2526: && (next_trial = next_active_insn (JUMP_LABEL (trial))) != 0 ! 2527: && ! (GET_CODE (next_trial) == INSN ! 2528: && GET_CODE (PATTERN (next_trial)) == SEQUENCE) ! 2529: && ! insn_references_resource_p (next_trial, &set, 1) ! 2530: && ! insn_sets_resource_p (next_trial, &set, 1) ! 2531: && ! insn_sets_resource_p (next_trial, &needed, 1) ! 2532: #ifdef HAVE_cc0 ! 2533: && ! (reg_mentioned_p (cc0_rtx, PATTERN (next_trial)) ! 2534: && ! sets_cc0_p (PATTERN (next_trial))) ! 2535: #endif ! 2536: && ! (maybe_never && may_trap_p (PATTERN (next_trial))) ! 2537: && (next_trial = try_split (PATTERN (next_trial), next_trial, 0)) ! 2538: && eligible_for_delay (insn, slots_filled, next_trial)) ! 2539: { ! 2540: rtx new_label = next_active_insn (next_trial); ! 2541: ! 2542: if (new_label != 0) ! 2543: new_label = get_label_before (new_label); ! 2544: ! 2545: delay_list ! 2546: = add_to_delay_list (copy_rtx (next_trial), delay_list); ! 2547: slots_filled++; ! 2548: redirect_jump (trial, new_label); ! 2549: ! 2550: /* If we merged because we both jumped to the same place, ! 2551: redirect the original insn also. */ ! 2552: if (target) ! 2553: redirect_jump (insn, new_label); ! 2554: } ! 2555: } ! 2556: ! 2557: if (delay_list) ! 2558: unfilled_slots_base[i] ! 2559: = emit_delay_sequence (insn, delay_list, ! 2560: slots_filled, slots_to_fill); ! 2561: ! 2562: if (slots_to_fill == slots_filled) ! 2563: unfilled_slots_base[i] = 0; ! 2564: ! 2565: note_delay_statistics (slots_filled, 0); ! 2566: } ! 2567: ! 2568: #ifdef DELAY_SLOTS_FOR_EPILOGUE ! 2569: /* See if the epilogue needs any delay slots. Try to fill them if so. ! 2570: The only thing we can do is scan backwards from the end of the ! 2571: function. If we did this in a previous pass, it is incorrect to do it ! 2572: again. */ ! 2573: if (current_function_epilogue_delay_list) ! 2574: return; ! 2575: ! 2576: slots_to_fill = DELAY_SLOTS_FOR_EPILOGUE; ! 2577: if (slots_to_fill == 0) ! 2578: return; ! 2579: ! 2580: slots_filled = 0; ! 2581: CLEAR_RESOURCE (&needed); ! 2582: CLEAR_RESOURCE (&set); ! 2583: ! 2584: for (trial = get_last_insn (); ! stop_search_p (trial, 1); ! 2585: trial = PREV_INSN (trial)) ! 2586: { ! 2587: if (GET_CODE (trial) == NOTE) ! 2588: continue; ! 2589: pat = PATTERN (trial); ! 2590: if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER) ! 2591: continue; ! 2592: ! 2593: if (! insn_references_resource_p (trial, &set, 1) ! 2594: && ! insn_sets_resource_p (trial, &needed, 1) ! 2595: #ifdef HAVE_cc0 ! 2596: /* Don't want to mess with cc0 here. */ ! 2597: && ! reg_mentioned_p (cc0_rtx, pat) ! 2598: #endif ! 2599: ) ! 2600: { ! 2601: trial = try_split (pat, trial, 1); ! 2602: if (ELIGIBLE_FOR_EPILOGUE_DELAY (trial, slots_filled)) ! 2603: { ! 2604: /* Here as well we are searching backward, so put the ! 2605: insns we find on the head of the list. */ ! 2606: ! 2607: current_function_epilogue_delay_list ! 2608: = gen_rtx (INSN_LIST, VOIDmode, trial, ! 2609: current_function_epilogue_delay_list); ! 2610: mark_referenced_resources (trial, &end_of_function_needs, 1); ! 2611: update_block (trial, trial); ! 2612: delete_insn (trial); ! 2613: ! 2614: /* Clear deleted bit so final.c will output the insn. */ ! 2615: INSN_DELETED_P (trial) = 0; ! 2616: ! 2617: if (slots_to_fill == ++slots_filled) ! 2618: break; ! 2619: continue; ! 2620: } ! 2621: } ! 2622: ! 2623: mark_set_resources (trial, &set, 1); ! 2624: mark_referenced_resources (trial, &needed, 1); ! 2625: } ! 2626: ! 2627: note_delay_statistics (slots_filled, 0); ! 2628: #endif ! 2629: } ! 2630: ! 2631: /* Try to find insns to place in delay slots. ! 2632: ! 2633: INSN is the jump needing SLOTS_TO_FILL delay slots. It tests CONDITION ! 2634: or is an unconditional branch if CONDITION is const_true_rtx. ! 2635: *PSLOTS_FILLED is updated with the number of slots that we have filled. ! 2636: ! 2637: THREAD is a flow-of-control, either the insns to be executed if the ! 2638: branch is true or if the branch is false, THREAD_IF_TRUE says which. ! 2639: ! 2640: OPPOSITE_THREAD is the thread in the opposite direction. It is used ! 2641: to see if any potential delay slot insns set things needed there. ! 2642: ! 2643: LIKELY is non-zero if it is extremely likely that the branch will be ! 2644: taken and THREAD_IF_TRUE is set. This is used for the branch at the ! 2645: end of a loop back up to the top. ! 2646: ! 2647: OWN_THREAD and OWN_OPPOSITE_THREAD are true if we are the only user of the ! 2648: thread. I.e., it is the fallthrough code of our jump or the target of the ! 2649: jump when we are the only jump going there. ! 2650: ! 2651: If OWN_THREAD is false, it must be the "true" thread of a jump. In that ! 2652: case, we can only take insns from the head of the thread for our delay ! 2653: slot. We then adjust the jump to point after the insns we have taken. */ ! 2654: ! 2655: static rtx ! 2656: fill_slots_from_thread (insn, condition, thread, opposite_thread, likely, ! 2657: thread_if_true, own_thread, own_opposite_thread, ! 2658: slots_to_fill, pslots_filled) ! 2659: rtx insn; ! 2660: rtx condition; ! 2661: rtx thread, opposite_thread; ! 2662: int likely; ! 2663: int thread_if_true; ! 2664: int own_thread, own_opposite_thread; ! 2665: int slots_to_fill, *pslots_filled; ! 2666: { ! 2667: rtx new_thread = thread; ! 2668: rtx delay_list = 0; ! 2669: struct resources opposite_needed, set, needed; ! 2670: rtx trial; ! 2671: int lose = 0; ! 2672: int must_annul = 0; ! 2673: ! 2674: /* Validate our arguments. */ ! 2675: if ((condition == const_true_rtx && ! thread_if_true) ! 2676: || (! own_thread && ! thread_if_true)) ! 2677: abort (); ! 2678: ! 2679: /* If our thread is the end of subroutine, we can't get any delay ! 2680: insns from that. */ ! 2681: if (thread == 0) ! 2682: return 0; ! 2683: ! 2684: /* If this is an unconditional branch, nothing is needed at the ! 2685: opposite thread. Otherwise, compute what is needed there. */ ! 2686: if (condition == const_true_rtx) ! 2687: CLEAR_RESOURCE (&opposite_needed); ! 2688: else ! 2689: mark_target_live_regs (opposite_thread, &opposite_needed); ! 2690: ! 2691: /* Scan insns at THREAD. We are looking for an insn that can be removed ! 2692: from THREAD (it neither sets nor references resources that were set ! 2693: ahead of it and it doesn't set anything needs by the insns ahead of ! 2694: it) and that either can be placed in an annulling insn or aren't ! 2695: needed at OPPOSITE_THREAD. */ ! 2696: ! 2697: CLEAR_RESOURCE (&needed); ! 2698: CLEAR_RESOURCE (&set); ! 2699: ! 2700: /* If we do not own this thread, we must stop as soon as we find ! 2701: something that we can't put in a delay slot, since all we can do ! 2702: is branch into THREAD at a later point. Therefore, labels stop ! 2703: the search if this is not the `true' thread. */ ! 2704: ! 2705: for (trial = thread; ! 2706: ! stop_search_p (trial, ! thread_if_true) && (! lose || own_thread); ! 2707: trial = next_nonnote_insn (trial)) ! 2708: { ! 2709: rtx pat; ! 2710: ! 2711: /* If we have passed a label, we no longer own this thread. */ ! 2712: if (GET_CODE (trial) == CODE_LABEL) ! 2713: { ! 2714: own_thread = 0; ! 2715: continue; ! 2716: } ! 2717: ! 2718: pat = PATTERN (trial); ! 2719: if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER) ! 2720: continue; ! 2721: ! 2722: /* If TRIAL conflicts with the insns ahead of it, we lose. Also, ! 2723: don't separate or copy insns that set and use CC0. */ ! 2724: if (! insn_references_resource_p (trial, &set, 1) ! 2725: && ! insn_sets_resource_p (trial, &set, 1) ! 2726: && ! insn_sets_resource_p (trial, &needed, 1) ! 2727: #ifdef HAVE_cc0 ! 2728: && ! (reg_mentioned_p (cc0_rtx, pat) ! 2729: && (! own_thread || ! sets_cc0_p (pat))) ! 2730: #endif ! 2731: ) ! 2732: { ! 2733: /* If TRIAL is redundant with some insn before INSN, we don't ! 2734: actually need to add it to the delay list; we can merely pretend ! 2735: we did. */ ! 2736: if (redundant_insn_p (trial, insn, delay_list)) ! 2737: { ! 2738: if (own_thread) ! 2739: { ! 2740: update_block (trial, thread); ! 2741: delete_insn (trial); ! 2742: } ! 2743: else ! 2744: new_thread = next_active_insn (trial); ! 2745: ! 2746: continue; ! 2747: } ! 2748: ! 2749: /* There are two ways we can win: If TRIAL doesn't set anything ! 2750: needed at the opposite thread and can't trap, or if it can ! 2751: go into an annulled delay slot. */ ! 2752: if (condition == const_true_rtx ! 2753: || (! insn_sets_resource_p (trial, &opposite_needed, 1) ! 2754: && ! may_trap_p (pat))) ! 2755: { ! 2756: trial = try_split (pat, trial, 0); ! 2757: pat = PATTERN (trial); ! 2758: if (eligible_for_delay (insn, *pslots_filled, trial)) ! 2759: goto winner; ! 2760: } ! 2761: else if (0 ! 2762: #ifdef ANNUL_IFTRUE_SLOTS ! 2763: || ! thread_if_true ! 2764: #endif ! 2765: #ifdef ANNUL_IFFALSE_SLOTS ! 2766: || thread_if_true ! 2767: #endif ! 2768: ) ! 2769: { ! 2770: trial = try_split (pat, trial, 0); ! 2771: pat = PATTERN (trial); ! 2772: if ((thread_if_true ! 2773: ? eligible_for_annul_false (insn, *pslots_filled, trial) ! 2774: : eligible_for_annul_true (insn, *pslots_filled, trial))) ! 2775: { ! 2776: rtx temp; ! 2777: ! 2778: must_annul = 1; ! 2779: winner: ! 2780: ! 2781: #ifdef HAVE_cc0 ! 2782: if (reg_mentioned_p (cc0_rtx, pat)) ! 2783: link_cc0_insns (trial); ! 2784: #endif ! 2785: ! 2786: /* If we own this thread, delete the insn. If this is the ! 2787: destination of a branch, show that a basic block status ! 2788: may have been updated. In any case, mark the new ! 2789: starting point of this thread. */ ! 2790: if (own_thread) ! 2791: { ! 2792: update_block (trial, thread); ! 2793: delete_insn (trial); ! 2794: } ! 2795: else ! 2796: new_thread = next_active_insn (trial); ! 2797: ! 2798: temp = own_thread ? trial : copy_rtx (trial); ! 2799: if (thread_if_true) ! 2800: INSN_FROM_TARGET_P (temp) = 1; ! 2801: ! 2802: delay_list = add_to_delay_list (temp, delay_list); ! 2803: ! 2804: if (slots_to_fill == ++(*pslots_filled)) ! 2805: { ! 2806: /* Even though we have filled all the slots, we ! 2807: may be branching to a location that has a ! 2808: redundant insn. Skip any if so. */ ! 2809: while (new_thread && ! own_thread ! 2810: && ! insn_sets_resource_p (new_thread, &set, 1) ! 2811: && ! insn_sets_resource_p (new_thread, &needed, 1) ! 2812: && ! insn_references_resource_p (new_thread, ! 2813: &set, 1) ! 2814: && redundant_insn_p (new_thread, insn, ! 2815: delay_list)) ! 2816: new_thread = next_active_insn (new_thread); ! 2817: break; ! 2818: } ! 2819: ! 2820: continue; ! 2821: } ! 2822: } ! 2823: } ! 2824: ! 2825: /* This insn can't go into a delay slot. */ ! 2826: lose = 1; ! 2827: mark_set_resources (trial, &set, 1); ! 2828: mark_referenced_resources (trial, &needed, 1); ! 2829: ! 2830: /* Ensure we don't put insns between the setting of cc and the comparison ! 2831: by moving a setting of cc into an earlier delay slot since these insns ! 2832: could clobber the condition code. */ ! 2833: set.cc = 1; ! 2834: ! 2835: /* If this insn is a register-register copy and the next insn has ! 2836: a use of our destination, change it to use our source. That way, ! 2837: it will become a candidate for our delay slot the next time ! 2838: through this loop. This case occurs commonly in loops that ! 2839: scan a list. ! 2840: ! 2841: We could check for more complex cases than those tested below, ! 2842: but it doesn't seem worth it. It might also be a good idea to try ! 2843: to swap the two insns. That might do better. */ ! 2844: ! 2845: if (GET_CODE (trial) == INSN && GET_CODE (pat) == SET ! 2846: && GET_CODE (SET_SRC (pat)) == REG ! 2847: && GET_CODE (SET_DEST (pat)) == REG) ! 2848: { ! 2849: rtx next = next_nonnote_insn (trial); ! 2850: int our_dest = REGNO (SET_DEST (pat)); ! 2851: ! 2852: if (next && GET_CODE (next) == INSN ! 2853: && GET_CODE (PATTERN (next)) == SET ! 2854: && GET_CODE (SET_DEST (PATTERN (next))) == REG ! 2855: && REGNO (SET_DEST (PATTERN (next))) != our_dest ! 2856: && refers_to_regno_p (our_dest, our_dest + 1, ! 2857: SET_SRC (PATTERN (next)), 0)) ! 2858: validate_replace_rtx (SET_DEST (pat), SET_SRC (pat), next); ! 2859: } ! 2860: } ! 2861: ! 2862: /* If we stopped on a branch insn that has delay slots, see if we can ! 2863: steal some of the insns in those slots. */ ! 2864: if (trial && GET_CODE (trial) == INSN ! 2865: && GET_CODE (PATTERN (trial)) == SEQUENCE ! 2866: && GET_CODE (XVECEXP (PATTERN (trial), 0, 0)) == JUMP_INSN) ! 2867: { ! 2868: /* If this is the `true' thread, we will want to follow the jump, ! 2869: so we can only do this if we have taken everything up to here. */ ! 2870: if (thread_if_true && trial == new_thread) ! 2871: delay_list ! 2872: = steal_delay_list_from_target (insn, condition, PATTERN (trial), ! 2873: delay_list, &set, &needed, ! 2874: &opposite_needed, slots_to_fill, ! 2875: pslots_filled, &must_annul, ! 2876: &new_thread); ! 2877: else if (! thread_if_true) ! 2878: delay_list ! 2879: = steal_delay_list_from_fallthrough (insn, condition, ! 2880: PATTERN (trial), ! 2881: delay_list, &set, &needed, ! 2882: &opposite_needed, slots_to_fill, ! 2883: pslots_filled, &must_annul); ! 2884: } ! 2885: ! 2886: /* If we haven't found anything for this delay slot and it is very ! 2887: likely that the branch will be taken, see if the insn at our target ! 2888: increments or decrements a register. If so, try to place the opposite ! 2889: arithmetic insn after the jump insn and put the arithmetic insn in the ! 2890: delay slot. If we can't do this, return. */ ! 2891: if (delay_list == 0 && likely && new_thread && GET_CODE (new_thread) == INSN) ! 2892: { ! 2893: rtx pat = PATTERN (new_thread); ! 2894: rtx dest; ! 2895: rtx src; ! 2896: ! 2897: trial = try_split (pat, new_thread, 0); ! 2898: pat = PATTERN (trial); ! 2899: ! 2900: if (GET_CODE (trial) != INSN || GET_CODE (pat) != SET ! 2901: || ! eligible_for_delay (insn, 0, trial)) ! 2902: return 0; ! 2903: ! 2904: dest = SET_DEST (pat), src = SET_SRC (pat); ! 2905: if ((GET_CODE (src) == PLUS || GET_CODE (src) == MINUS) ! 2906: && rtx_equal_p (XEXP (src, 0), dest)) ! 2907: { ! 2908: rtx other = XEXP (src, 1); ! 2909: rtx new_arith; ! 2910: rtx ninsn; ! 2911: ! 2912: /* If this is a constant adjustment, use the same code with ! 2913: the negated constant. Otherwise, reverse the sense of the ! 2914: arithmetic. */ ! 2915: if (GET_CODE (other) == CONST_INT) ! 2916: new_arith = gen_rtx (GET_CODE (src), GET_MODE (src), dest, ! 2917: negate_rtx (GET_MODE (src), other)); ! 2918: else ! 2919: new_arith = gen_rtx (GET_CODE (src) == PLUS ? MINUS : PLUS, ! 2920: GET_MODE (src), dest, other); ! 2921: ! 2922: ninsn = emit_insn_after (gen_rtx (SET, VOIDmode, dest, new_arith), ! 2923: insn); ! 2924: ! 2925: if (recog_memoized (ninsn) < 0 ! 2926: || (insn_extract (ninsn), ! 2927: ! constrain_operands (INSN_CODE (ninsn), 1))) ! 2928: { ! 2929: delete_insn (ninsn); ! 2930: return 0; ! 2931: } ! 2932: ! 2933: if (own_thread) ! 2934: { ! 2935: update_block (trial, thread); ! 2936: delete_insn (trial); ! 2937: } ! 2938: else ! 2939: new_thread = next_active_insn (trial); ! 2940: ! 2941: ninsn = own_thread ? trial : copy_rtx (trial); ! 2942: if (thread_if_true) ! 2943: INSN_FROM_TARGET_P (ninsn) = 1; ! 2944: ! 2945: delay_list = add_to_delay_list (ninsn, 0); ! 2946: (*pslots_filled)++; ! 2947: } ! 2948: } ! 2949: ! 2950: if (delay_list && must_annul) ! 2951: INSN_ANNULLED_BRANCH_P (insn) = 1; ! 2952: ! 2953: /* If we are to branch into the middle of this thread, find an appropriate ! 2954: label or make a new one if none, and redirect INSN to it. If we hit the ! 2955: end of the function, use the end-of-function label. */ ! 2956: if (new_thread != thread) ! 2957: { ! 2958: rtx label; ! 2959: ! 2960: if (! thread_if_true) ! 2961: abort (); ! 2962: ! 2963: if (new_thread && GET_CODE (new_thread) == JUMP_INSN ! 2964: && (simplejump_p (new_thread) ! 2965: || GET_CODE (PATTERN (new_thread)) == RETURN)) ! 2966: new_thread = follow_jumps (JUMP_LABEL (new_thread), 1); ! 2967: ! 2968: if (new_thread == 0) ! 2969: label = find_end_label (); ! 2970: else if (GET_CODE (new_thread) == CODE_LABEL) ! 2971: label = new_thread; ! 2972: else ! 2973: label = get_label_before (new_thread); ! 2974: ! 2975: redirect_jump (insn, label); ! 2976: } ! 2977: ! 2978: return delay_list; ! 2979: } ! 2980: ! 2981: /* Make another attempt to find insns to place in delay slots. ! 2982: ! 2983: We previously looked for insns located in front of the delay insn ! 2984: and, for non-jump delay insns, located behind the delay insn. ! 2985: ! 2986: Here only try to schedule jump insns and try to move insns from either ! 2987: the target or the following insns into the delay slot. If annulling is ! 2988: supported, we will be likely to do this. Otherwise, we can do this only ! 2989: if safe. */ ! 2990: ! 2991: static void ! 2992: fill_eager_delay_slots (first) ! 2993: rtx first; ! 2994: { ! 2995: register rtx insn; ! 2996: register int i; ! 2997: int num_unfilled_slots = unfilled_slots_next - unfilled_slots_base; ! 2998: ! 2999: for (i = 0; i < num_unfilled_slots; i++) ! 3000: { ! 3001: rtx condition; ! 3002: rtx target_label, insn_at_target, fallthrough_insn; ! 3003: rtx delay_list = 0; ! 3004: int own_target; ! 3005: int own_fallthrough; ! 3006: int prediction, slots_to_fill, slots_filled; ! 3007: ! 3008: insn = unfilled_slots_base[i]; ! 3009: if (insn == 0 ! 3010: || INSN_DELETED_P (insn) ! 3011: || GET_CODE (insn) != JUMP_INSN ! 3012: || ! condjump_p (insn)) ! 3013: continue; ! 3014: ! 3015: slots_to_fill = num_delay_slots (insn); ! 3016: if (slots_to_fill == 0) ! 3017: abort (); ! 3018: ! 3019: slots_filled = 0; ! 3020: target_label = JUMP_LABEL (insn); ! 3021: condition = get_branch_condition (insn, target_label); ! 3022: ! 3023: if (condition == 0) ! 3024: continue; ! 3025: ! 3026: /* Get the next active fallthough and target insns and see if we own ! 3027: them. Then see whether the branch is likely true. We don't need ! 3028: to do a lot of this for unconditional branches. */ ! 3029: ! 3030: insn_at_target = next_active_insn (target_label); ! 3031: own_target = own_thread_p (target_label, target_label, 0); ! 3032: ! 3033: if (condition == const_true_rtx) ! 3034: { ! 3035: own_fallthrough = 0; ! 3036: fallthrough_insn = 0; ! 3037: prediction = 2; ! 3038: } ! 3039: else ! 3040: { ! 3041: fallthrough_insn = next_active_insn (insn); ! 3042: own_fallthrough = own_thread_p (NEXT_INSN (insn), 0, 1); ! 3043: prediction = mostly_true_jump (insn, condition); ! 3044: } ! 3045: ! 3046: /* If this insn is expected to branch, first try to get insns from our ! 3047: target, then our fallthrough insns. If it is not, expected to branch, ! 3048: try the other order. */ ! 3049: ! 3050: if (prediction) ! 3051: { ! 3052: delay_list ! 3053: = fill_slots_from_thread (insn, condition, insn_at_target, ! 3054: fallthrough_insn, prediction == 2, 1, ! 3055: own_target, own_fallthrough, ! 3056: slots_to_fill, &slots_filled); ! 3057: ! 3058: if (delay_list == 0 && own_fallthrough) ! 3059: { ! 3060: /* Even though we didn't find anything for delay slots, ! 3061: we might have found a redundant insn which we deleted ! 3062: from the thread that was filled. So we have to recompute ! 3063: the next insn at the target. */ ! 3064: target_label = JUMP_LABEL (insn); ! 3065: insn_at_target = next_active_insn (target_label); ! 3066: ! 3067: delay_list ! 3068: = fill_slots_from_thread (insn, condition, fallthrough_insn, ! 3069: insn_at_target, 0, 0, ! 3070: own_fallthrough, own_target, ! 3071: slots_to_fill, &slots_filled); ! 3072: } ! 3073: } ! 3074: else ! 3075: { ! 3076: if (own_fallthrough) ! 3077: delay_list ! 3078: = fill_slots_from_thread (insn, condition, fallthrough_insn, ! 3079: insn_at_target, 0, 0, ! 3080: own_fallthrough, own_target, ! 3081: slots_to_fill, &slots_filled); ! 3082: ! 3083: if (delay_list == 0) ! 3084: delay_list ! 3085: = fill_slots_from_thread (insn, condition, insn_at_target, ! 3086: next_active_insn (insn), 0, 1, ! 3087: own_target, own_fallthrough, ! 3088: slots_to_fill, &slots_filled); ! 3089: } ! 3090: ! 3091: if (delay_list) ! 3092: unfilled_slots_base[i] ! 3093: = emit_delay_sequence (insn, delay_list, ! 3094: slots_filled, slots_to_fill); ! 3095: ! 3096: if (slots_to_fill == slots_filled) ! 3097: unfilled_slots_base[i] = 0; ! 3098: ! 3099: note_delay_statistics (slots_filled, 1); ! 3100: } ! 3101: } ! 3102: ! 3103: /* Once we have tried two ways to fill a delay slot, make a pass over the ! 3104: code to try to improve the results and to do such things as more jump ! 3105: threading. */ ! 3106: ! 3107: static void ! 3108: relax_delay_slots (first) ! 3109: rtx first; ! 3110: { ! 3111: register rtx insn, next, pat; ! 3112: register rtx trial, delay_insn, target_label; ! 3113: ! 3114: /* Look at every JUMP_INSN and see if we can improve it. */ ! 3115: for (insn = first; insn; insn = next) ! 3116: { ! 3117: rtx other; ! 3118: ! 3119: next = next_active_insn (insn); ! 3120: ! 3121: /* If this is a jump insn, see if it now jumps to a jump, jumps to ! 3122: the next insn, or jumps to a label that is not the last of a ! 3123: group of consecutive labels. */ ! 3124: if (GET_CODE (insn) == JUMP_INSN ! 3125: && (target_label = JUMP_LABEL (insn)) != 0) ! 3126: { ! 3127: target_label = follow_jumps (target_label, 1); ! 3128: target_label = prev_label (next_active_insn (target_label)); ! 3129: ! 3130: if (next_active_insn (target_label) == next) ! 3131: { ! 3132: delete_jump (insn); ! 3133: continue; ! 3134: } ! 3135: ! 3136: if (target_label != JUMP_LABEL (insn)) ! 3137: redirect_jump (insn, ! 3138: target_label ? target_label : find_end_label ()); ! 3139: ! 3140: /* See if this jump branches around a unconditional jump. ! 3141: If so, invert this jump and point it to the target of the ! 3142: second jump. */ ! 3143: if (next && GET_CODE (next) == JUMP_INSN ! 3144: && (simplejump_p (next) || GET_CODE (PATTERN (next)) == RETURN) ! 3145: && next_active_insn (target_label) == next_active_insn (next) ! 3146: && no_labels_between_p (insn, next)) ! 3147: { ! 3148: rtx label = JUMP_LABEL (next); ! 3149: ! 3150: /* Be careful how we do this to avoid deleting code or ! 3151: labels that are momentarily dead. See similar optimization ! 3152: in jump.c. ! 3153: ! 3154: We also need to ensure we properly handle the case when ! 3155: invert_jump fails. */ ! 3156: ! 3157: ++LABEL_NUSES (target_label); ! 3158: if (label) ! 3159: ++LABEL_NUSES (label); ! 3160: ! 3161: if (invert_jump (insn, label)) ! 3162: { ! 3163: delete_insn (next); ! 3164: next = insn; ! 3165: } ! 3166: ! 3167: if (label) ! 3168: --LABEL_NUSES (label); ! 3169: ! 3170: if (--LABEL_NUSES (target_label) == 0) ! 3171: delete_insn (target_label); ! 3172: ! 3173: continue; ! 3174: } ! 3175: } ! 3176: ! 3177: /* If this is an unconditional jump and the previous insn is a ! 3178: conditional jump, try reversing the condition of the previous ! 3179: insn and swapping our targets. The next pass might be able to ! 3180: fill the slots. ! 3181: ! 3182: Don't do this if we expect the conditional branch to be true, because ! 3183: we would then be making the more common case longer. */ ! 3184: ! 3185: if (GET_CODE (insn) == JUMP_INSN ! 3186: && (simplejump_p (insn) || GET_CODE (PATTERN (insn)) == RETURN) ! 3187: && (other = prev_active_insn (insn)) != 0 ! 3188: && condjump_p (other) ! 3189: && no_labels_between_p (other, insn) ! 3190: && ! mostly_true_jump (other, ! 3191: get_branch_condition (other, ! 3192: JUMP_LABEL (other)))) ! 3193: { ! 3194: rtx other_target = JUMP_LABEL (other); ! 3195: ! 3196: /* Increment the count of OTHER_TARGET, so it doesn't get deleted ! 3197: as we move the label. */ ! 3198: if (other_target) ! 3199: ++LABEL_NUSES (other_target); ! 3200: ! 3201: if (invert_jump (other, target_label)) ! 3202: redirect_jump (insn, other_target); ! 3203: ! 3204: if (other_target) ! 3205: --LABEL_NUSES (other_target); ! 3206: } ! 3207: ! 3208: /* Now look only at cases where we have filled a delay slot. */ ! 3209: if (GET_CODE (insn) != INSN ! 3210: || GET_CODE (PATTERN (insn)) != SEQUENCE) ! 3211: continue; ! 3212: ! 3213: pat = PATTERN (insn); ! 3214: delay_insn = XVECEXP (pat, 0, 0); ! 3215: ! 3216: /* See if the first insn in the delay slot is redundant with some ! 3217: previous insn. Remove it from the delay slot if so; then set up ! 3218: to reprocess this insn. */ ! 3219: if (redundant_insn_p (XVECEXP (pat, 0, 1), delay_insn, 0)) ! 3220: { ! 3221: delete_from_delay_slot (XVECEXP (pat, 0, 1)); ! 3222: next = prev_active_insn (next); ! 3223: continue; ! 3224: } ! 3225: ! 3226: /* Now look only at the cases where we have a filled JUMP_INSN. */ ! 3227: if (GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) != JUMP_INSN ! 3228: || ! condjump_p (XVECEXP (PATTERN (insn), 0, 0))) ! 3229: continue; ! 3230: ! 3231: target_label = JUMP_LABEL (delay_insn); ! 3232: ! 3233: if (target_label) ! 3234: { ! 3235: /* If this jump goes to another unconditional jump, thread it, but ! 3236: don't convert a jump into a RETURN here. */ ! 3237: trial = follow_jumps (target_label, 1); ! 3238: trial = prev_label (next_active_insn (trial)); ! 3239: if (trial == 0 && target_label != 0) ! 3240: trial = find_end_label (); ! 3241: ! 3242: if (trial != target_label) ! 3243: { ! 3244: redirect_jump (delay_insn, trial); ! 3245: target_label = trial; ! 3246: } ! 3247: ! 3248: /* If the first insn at TARGET_LABEL is redundant with a previous ! 3249: insn, redirect the jump to the following insn process again. */ ! 3250: trial = next_active_insn (target_label); ! 3251: if (trial && GET_CODE (PATTERN (trial)) != SEQUENCE ! 3252: && redundant_insn_p (trial, insn, 0)) ! 3253: { ! 3254: trial = next_active_insn (trial); ! 3255: if (trial == 0) ! 3256: target_label = find_end_label (); ! 3257: else ! 3258: target_label = get_label_before (trial); ! 3259: redirect_jump (delay_insn, target_label); ! 3260: next = insn; ! 3261: continue; ! 3262: } ! 3263: ! 3264: /* Similarly, if it is an unconditional jump with one insn in its ! 3265: delay list and that insn is redundant, thread the jump. */ ! 3266: if (trial && GET_CODE (PATTERN (trial)) == SEQUENCE ! 3267: && XVECLEN (PATTERN (trial), 0) == 2 ! 3268: && GET_CODE (XVECEXP (PATTERN (trial), 0, 0)) == JUMP_INSN ! 3269: && (simplejump_p (XVECEXP (PATTERN (trial), 0, 0)) ! 3270: || GET_CODE (PATTERN (XVECEXP (PATTERN (trial), 0, 0))) == RETURN) ! 3271: && redundant_insn_p (XVECEXP (PATTERN (trial), 0, 1), insn, 0)) ! 3272: { ! 3273: target_label = JUMP_LABEL (XVECEXP (PATTERN (trial), 0, 0)); ! 3274: if (target_label == 0) ! 3275: target_label = find_end_label (); ! 3276: redirect_jump (delay_insn, target_label); ! 3277: next = insn; ! 3278: continue; ! 3279: } ! 3280: } ! 3281: ! 3282: if (! INSN_ANNULLED_BRANCH_P (delay_insn) ! 3283: && prev_active_insn (target_label) == insn ! 3284: #ifdef HAVE_cc0 ! 3285: /* If the last insn in the delay slot sets CC0 for some insn, ! 3286: various code assumes that it is in a delay slot. We could ! 3287: put it back where it belonged and delete the register notes, ! 3288: but it doesn't seem worhwhile in this uncommon case. */ ! 3289: && ! find_reg_note (XVECEXP (pat, 0, XVECLEN (pat, 0) - 1), ! 3290: REG_CC_USER, 0) ! 3291: #endif ! 3292: ) ! 3293: { ! 3294: /* All this insn does is execute its delay list and jump to the ! 3295: following insn. So delete the jump and just execute the delay ! 3296: list insns. ! 3297: ! 3298: We do this by deleting the INSN containing the SEQUENCE, then ! 3299: re-emitting the insns separately, and then deleting the jump. ! 3300: This allows the count of the jump target to be properly ! 3301: decremented. */ ! 3302: ! 3303: trial = PREV_INSN (insn); ! 3304: delete_insn (insn); ! 3305: emit_insn_after (pat, trial); ! 3306: delete_scheduled_jump (delay_insn); ! 3307: continue; ! 3308: } ! 3309: ! 3310: /* See if this jump (with its delay slots) branches around another ! 3311: jump (without delay slots). If so, invert this jump and point ! 3312: it to the target of the second jump. We cannot do this for ! 3313: annulled jumps, though. Again, don't convert a jump to a RETURN ! 3314: here. */ ! 3315: if (! INSN_ANNULLED_BRANCH_P (delay_insn) ! 3316: && next && GET_CODE (next) == JUMP_INSN ! 3317: && (simplejump_p (next) || GET_CODE (PATTERN (next)) == RETURN) ! 3318: && next_active_insn (target_label) == next_active_insn (next) ! 3319: && no_labels_between_p (insn, next)) ! 3320: { ! 3321: rtx label = JUMP_LABEL (next); ! 3322: rtx old_label = JUMP_LABEL (delay_insn); ! 3323: ! 3324: if (label == 0) ! 3325: label = find_end_label (); ! 3326: ! 3327: /* Be careful how we do this to avoid deleting code or labels ! 3328: that are momentarily dead. See similar optimization in jump.c */ ! 3329: if (old_label) ! 3330: ++LABEL_NUSES (old_label); ! 3331: ! 3332: if (invert_jump (delay_insn, label)) ! 3333: { ! 3334: delete_insn (next); ! 3335: next = insn; ! 3336: } ! 3337: ! 3338: if (old_label && --LABEL_NUSES (old_label) == 0) ! 3339: delete_insn (old_label); ! 3340: continue; ! 3341: } ! 3342: ! 3343: /* If we own the thread opposite the way this insn branches, see if we ! 3344: can merge its delay slots with following insns. */ ! 3345: if (INSN_FROM_TARGET_P (XVECEXP (pat, 0, 1)) ! 3346: && own_thread_p (NEXT_INSN (insn), 0, 1)) ! 3347: try_merge_delay_insns (insn, next); ! 3348: else if (! INSN_FROM_TARGET_P (XVECEXP (pat, 0, 1)) ! 3349: && own_thread_p (target_label, target_label, 0)) ! 3350: try_merge_delay_insns (insn, next_active_insn (target_label)); ! 3351: ! 3352: /* If we get here, we haven't deleted INSN. But we may have deleted ! 3353: NEXT, so recompute it. */ ! 3354: next = next_active_insn (insn); ! 3355: } ! 3356: } ! 3357: ! 3358: #ifdef HAVE_return ! 3359: ! 3360: /* Look for filled jumps to the end of function label. We can try to convert ! 3361: them into RETURN insns if the insns in the delay slot are valid for the ! 3362: RETURN as well. */ ! 3363: ! 3364: static void ! 3365: make_return_insns (first) ! 3366: rtx first; ! 3367: { ! 3368: rtx insn, jump_insn, pat; ! 3369: rtx real_return_label = end_of_function_label; ! 3370: int slots, i; ! 3371: ! 3372: /* See if there is a RETURN insn in the function other than the one we ! 3373: made for END_OF_FUNCTION_LABEL. If so, set up anything we can't change ! 3374: into a RETURN to jump to it. */ ! 3375: for (insn = first; insn; insn = NEXT_INSN (insn)) ! 3376: if (GET_CODE (insn) == JUMP_INSN && GET_CODE (PATTERN (insn)) == RETURN) ! 3377: { ! 3378: real_return_label = get_label_before (insn); ! 3379: break; ! 3380: } ! 3381: ! 3382: /* Show an extra usage of REAL_RETURN_LABEL so it won't go away if it ! 3383: was equal to END_OF_FUNCTION_LABEL. */ ! 3384: LABEL_NUSES (real_return_label)++; ! 3385: ! 3386: /* Clear the list of insns to fill so we can use it. */ ! 3387: obstack_free (&unfilled_slots_obstack, unfilled_firstobj); ! 3388: ! 3389: for (insn = first; insn; insn = NEXT_INSN (insn)) ! 3390: { ! 3391: /* Only look at filled JUMP_INSNs that go to the end of function ! 3392: label. */ ! 3393: if (GET_CODE (insn) != INSN ! 3394: || GET_CODE (PATTERN (insn)) != SEQUENCE ! 3395: || GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) != JUMP_INSN ! 3396: || JUMP_LABEL (XVECEXP (PATTERN (insn), 0, 0)) != end_of_function_label) ! 3397: continue; ! 3398: ! 3399: pat = PATTERN (insn); ! 3400: jump_insn = XVECEXP (pat, 0, 0); ! 3401: ! 3402: /* If we can't make the jump into a RETURN, redirect it to the best ! 3403: RETURN and go on to the next insn. */ ! 3404: if (! redirect_jump (jump_insn, 0)) ! 3405: { ! 3406: redirect_jump (jump_insn, real_return_label); ! 3407: continue; ! 3408: } ! 3409: ! 3410: /* See if this RETURN can accept the insns current in its delay slot. ! 3411: It can if it has more or an equal number of slots and the contents ! 3412: of each is valid. */ ! 3413: ! 3414: slots = num_delay_slots (jump_insn); ! 3415: if (slots >= XVECLEN (pat, 0) - 1) ! 3416: { ! 3417: for (i = 1; i < XVECLEN (pat, 0); i++) ! 3418: if (! ( ! 3419: #ifdef ANNUL_IFFALSE_SLOTS ! 3420: (INSN_ANNULLED_BRANCH_P (jump_insn) ! 3421: && INSN_FROM_TARGET_P (XVECEXP (pat, 0, i))) ! 3422: ? eligible_for_annul_false (jump_insn, i - 1, ! 3423: XVECEXP (pat, 0, i)) : ! 3424: #endif ! 3425: #ifdef ANNUL_IFTRUE_SLOTS ! 3426: (INSN_ANNULLED_BRANCH_P (jump_insn) ! 3427: && ! INSN_FROM_TARGET_P (XVECEXP (pat, 0, i))) ! 3428: ? eligible_for_annul_true (jump_insn, i - 1, ! 3429: XVECEXP (pat, 0, i)) : ! 3430: #endif ! 3431: eligible_for_delay (jump_insn, i -1, XVECEXP (pat, 0, i)))) ! 3432: break; ! 3433: } ! 3434: else ! 3435: i = 0; ! 3436: ! 3437: if (i == XVECLEN (pat, 0)) ! 3438: continue; ! 3439: ! 3440: /* We have to do something with this insn. If it is an unconditional ! 3441: RETURN, delete the SEQUENCE and output the individual insns, ! 3442: followed by the RETURN. Then set things up so we try to find ! 3443: insns for its delay slots, if it needs some. */ ! 3444: if (GET_CODE (PATTERN (jump_insn)) == RETURN) ! 3445: { ! 3446: rtx prev = PREV_INSN (insn); ! 3447: ! 3448: delete_insn (insn); ! 3449: for (i = 1; i < XVECLEN (pat, 0); i++) ! 3450: prev = emit_insn_after (PATTERN (XVECEXP (pat, 0, i)), prev); ! 3451: ! 3452: insn = emit_jump_insn_after (PATTERN (jump_insn), prev); ! 3453: emit_barrier_after (insn); ! 3454: ! 3455: if (slots) ! 3456: obstack_ptr_grow (&unfilled_slots_obstack, insn); ! 3457: } ! 3458: else ! 3459: /* It is probably more efficient to keep this with its current ! 3460: delay slot as a branch to a RETURN. */ ! 3461: redirect_jump (jump_insn, real_return_label); ! 3462: } ! 3463: ! 3464: /* Now delete REAL_RETURN_LABEL if we never used it. Then try to fill any ! 3465: new delay slots we have created. */ ! 3466: if (--LABEL_NUSES (real_return_label) == 0) ! 3467: delete_insn (real_return_label); ! 3468: ! 3469: fill_simple_delay_slots (first, 1); ! 3470: fill_simple_delay_slots (first, 0); ! 3471: } ! 3472: #endif ! 3473: ! 3474: /* Try to find insns to place in delay slots. */ ! 3475: ! 3476: void ! 3477: dbr_schedule (first, file) ! 3478: rtx first; ! 3479: FILE *file; ! 3480: { ! 3481: rtx insn, next; ! 3482: int i; ! 3483: #if 0 ! 3484: int old_flag_no_peephole = flag_no_peephole; ! 3485: ! 3486: /* Execute `final' once in prescan mode to delete any insns that won't be ! 3487: used. Don't let final try to do any peephole optimization--it will ! 3488: ruin dataflow information for this pass. */ ! 3489: ! 3490: flag_no_peephole = 1; ! 3491: final (first, 0, NO_DEBUG, 1, 1); ! 3492: flag_no_peephole = old_flag_no_peephole; ! 3493: #endif ! 3494: ! 3495: /* Find the highest INSN_UID and allocate and initialize our map from ! 3496: INSN_UID's to position in code. */ ! 3497: for (max_uid = 0, insn = first; insn; insn = NEXT_INSN (insn)) ! 3498: if (INSN_UID (insn) > max_uid) ! 3499: max_uid = INSN_UID (insn); ! 3500: ! 3501: uid_to_ruid = (int *) alloca ((max_uid + 1) * sizeof (int *)); ! 3502: for (i = 0, insn = first; insn; i++, insn = NEXT_INSN (insn)) ! 3503: uid_to_ruid[INSN_UID (insn)] = i; ! 3504: ! 3505: /* Initialize the list of insns that need filling. */ ! 3506: if (unfilled_firstobj == 0) ! 3507: { ! 3508: gcc_obstack_init (&unfilled_slots_obstack); ! 3509: unfilled_firstobj = (rtx *) obstack_alloc (&unfilled_slots_obstack, 0); ! 3510: } ! 3511: ! 3512: for (insn = next_active_insn (first); insn; insn = next_active_insn (insn)) ! 3513: { ! 3514: rtx target; ! 3515: ! 3516: INSN_ANNULLED_BRANCH_P (insn) = 0; ! 3517: INSN_FROM_TARGET_P (insn) = 0; ! 3518: ! 3519: /* Skip vector tables. We can't get attributes for them. */ ! 3520: if (GET_CODE (insn) == JUMP_INSN ! 3521: && (GET_CODE (PATTERN (insn)) == ADDR_VEC ! 3522: || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)) ! 3523: continue; ! 3524: ! 3525: if (num_delay_slots (insn) > 0) ! 3526: obstack_ptr_grow (&unfilled_slots_obstack, insn); ! 3527: ! 3528: /* Ensure all jumps go to the last of a set of consecutive labels. */ ! 3529: if (GET_CODE (insn) == JUMP_INSN && condjump_p (insn) ! 3530: && JUMP_LABEL (insn) != 0 ! 3531: && ((target = prev_label (next_active_insn (JUMP_LABEL (insn)))) ! 3532: != JUMP_LABEL (insn))) ! 3533: redirect_jump (insn, target); ! 3534: } ! 3535: ! 3536: /* Indicate what resources are required to be valid at the end of the current ! 3537: function. The condition code never is and memory always is. If the ! 3538: frame pointer is needed, it is and so is the stack pointer unless ! 3539: EXIT_IGNORE_STACK is non-zero. If the frame pointer is not needed, the ! 3540: stack pointer is. In addition, registers used to return the function ! 3541: value are needed. */ ! 3542: ! 3543: end_of_function_needs.cc = 0; ! 3544: end_of_function_needs.memory = 1; ! 3545: CLEAR_HARD_REG_SET (end_of_function_needs.regs); ! 3546: ! 3547: if (frame_pointer_needed) ! 3548: { ! 3549: SET_HARD_REG_BIT (end_of_function_needs.regs, FRAME_POINTER_REGNUM); ! 3550: #ifdef EXIT_IGNORE_STACK ! 3551: if (! EXIT_IGNORE_STACK) ! 3552: #endif ! 3553: SET_HARD_REG_BIT (end_of_function_needs.regs, STACK_POINTER_REGNUM); ! 3554: } ! 3555: else ! 3556: SET_HARD_REG_BIT (end_of_function_needs.regs, STACK_POINTER_REGNUM); ! 3557: ! 3558: if (current_function_return_rtx != 0 ! 3559: && GET_CODE (current_function_return_rtx) == REG) ! 3560: mark_referenced_resources (current_function_return_rtx, ! 3561: &end_of_function_needs, 0); ! 3562: ! 3563: /* Show we haven't computed an end-of-function label yet. */ ! 3564: end_of_function_label = 0; ! 3565: ! 3566: /* Allocate and initialize the tables used by mark_target_live_regs. */ ! 3567: target_hash_table ! 3568: = (struct target_info **) alloca ((TARGET_HASH_PRIME ! 3569: * sizeof (struct target_info *))); ! 3570: bzero (target_hash_table, TARGET_HASH_PRIME * sizeof (struct target_info *)); ! 3571: ! 3572: bb_ticks = (int *) alloca (n_basic_blocks * sizeof (int)); ! 3573: bzero (bb_ticks, n_basic_blocks * sizeof (int)); ! 3574: ! 3575: /* Initialize the statistics for this function. */ ! 3576: bzero (num_insns_needing_delays, sizeof num_insns_needing_delays); ! 3577: bzero (num_filled_delays, sizeof num_filled_delays); ! 3578: ! 3579: /* Now do the delay slot filling. Try everything twice in case earlier ! 3580: changes make more slots fillable. */ ! 3581: ! 3582: for (reorg_pass_number = 0; ! 3583: reorg_pass_number < MAX_REORG_PASSES; ! 3584: reorg_pass_number++) ! 3585: { ! 3586: fill_simple_delay_slots (first, 1); ! 3587: fill_simple_delay_slots (first, 0); ! 3588: fill_eager_delay_slots (first); ! 3589: relax_delay_slots (first); ! 3590: } ! 3591: ! 3592: /* Delete any USE insns made by update_block; subsequent passes don't need ! 3593: them or know how to deal with them. */ ! 3594: for (insn = first; insn; insn = next) ! 3595: { ! 3596: next = NEXT_INSN (insn); ! 3597: ! 3598: if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == USE ! 3599: && (GET_CODE (XEXP (PATTERN (insn), 0)) == INSN ! 3600: || GET_CODE (XEXP (PATTERN (insn), 0)) == JUMP_INSN ! 3601: || GET_CODE (XEXP (PATTERN (insn), 0)) == CALL_INSN)) ! 3602: next = delete_insn (insn); ! 3603: } ! 3604: ! 3605: /* If we made an end of function label, indicate that it is now ! 3606: safe to delete it by undoing our prior adjustment to LABEL_NUSES. ! 3607: If it is now unused, delete it. */ ! 3608: if (end_of_function_label && --LABEL_NUSES (end_of_function_label) == 0) ! 3609: delete_insn (end_of_function_label); ! 3610: ! 3611: #ifdef HAVE_return ! 3612: if (HAVE_return && end_of_function_label != 0) ! 3613: make_return_insns (first); ! 3614: #endif ! 3615: ! 3616: obstack_free (&unfilled_slots_obstack, unfilled_firstobj); ! 3617: ! 3618: /* It is not clear why the line below is needed, but it does seem to be. */ ! 3619: unfilled_firstobj = (rtx *) obstack_alloc (&unfilled_slots_obstack, 0); ! 3620: ! 3621: if (file) ! 3622: { ! 3623: register int i, j, need_comma; ! 3624: ! 3625: for (reorg_pass_number = 0; ! 3626: reorg_pass_number < MAX_REORG_PASSES; ! 3627: reorg_pass_number++) ! 3628: { ! 3629: fprintf (file, ";; Reorg pass #%d:\n", reorg_pass_number + 1); ! 3630: for (i = 0; i < NUM_REORG_FUNCTIONS; i++) ! 3631: { ! 3632: need_comma = 0; ! 3633: fprintf (file, ";; Reorg function #%d\n", i); ! 3634: ! 3635: fprintf (file, ";; %d insns needing delay slots\n;; ", ! 3636: num_insns_needing_delays[i][reorg_pass_number]); ! 3637: ! 3638: for (j = 0; j < MAX_DELAY_HISTOGRAM; j++) ! 3639: if (num_filled_delays[i][j][reorg_pass_number]) ! 3640: { ! 3641: if (need_comma) ! 3642: fprintf (file, ", "); ! 3643: need_comma = 1; ! 3644: fprintf (file, "%d got %d delays", ! 3645: num_filled_delays[i][j][reorg_pass_number], j); ! 3646: } ! 3647: fprintf (file, "\n"); ! 3648: } ! 3649: } ! 3650: } ! 3651: } ! 3652: #endif /* DELAY_SLOTS */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.