190075Sobrien/* Register renaming for the GNU compiler. 2169689Skan Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 3169689Skan Free Software Foundation, Inc. 490075Sobrien 590075Sobrien This file is part of GCC. 690075Sobrien 790075Sobrien GCC is free software; you can redistribute it and/or modify it 890075Sobrien under the terms of the GNU General Public License as published by 990075Sobrien the Free Software Foundation; either version 2, or (at your option) 1090075Sobrien any later version. 1190075Sobrien 1290075Sobrien GCC is distributed in the hope that it will be useful, but WITHOUT 1390075Sobrien ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 1490075Sobrien or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 1590075Sobrien License for more details. 1690075Sobrien 1790075Sobrien You should have received a copy of the GNU General Public License 1890075Sobrien along with GCC; see the file COPYING. If not, write to the Free 19169689Skan Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 20169689Skan 02110-1301, USA. */ 2190075Sobrien 2290075Sobrien#include "config.h" 2390075Sobrien#include "system.h" 24132718Skan#include "coretypes.h" 25132718Skan#include "tm.h" 2690075Sobrien#include "rtl.h" 2790075Sobrien#include "tm_p.h" 2890075Sobrien#include "insn-config.h" 2990075Sobrien#include "regs.h" 30169689Skan#include "addresses.h" 3190075Sobrien#include "hard-reg-set.h" 3290075Sobrien#include "basic-block.h" 3390075Sobrien#include "reload.h" 3490075Sobrien#include "output.h" 3590075Sobrien#include "function.h" 3690075Sobrien#include "recog.h" 3790075Sobrien#include "flags.h" 3890075Sobrien#include "toplev.h" 3990075Sobrien#include "obstack.h" 40169689Skan#include "timevar.h" 41169689Skan#include "tree-pass.h" 4290075Sobrien 4390075Sobrienstruct du_chain 4490075Sobrien{ 4590075Sobrien struct du_chain *next_chain; 4690075Sobrien struct du_chain *next_use; 4790075Sobrien 4890075Sobrien rtx insn; 4990075Sobrien rtx *loc; 50169689Skan ENUM_BITFIELD(reg_class) cl : 16; 5190075Sobrien unsigned int need_caller_save_reg:1; 5290075Sobrien unsigned int earlyclobber:1; 5390075Sobrien}; 5490075Sobrien 5590075Sobrienenum scan_actions 5690075Sobrien{ 5790075Sobrien terminate_all_read, 5890075Sobrien terminate_overlapping_read, 5990075Sobrien terminate_write, 6090075Sobrien terminate_dead, 6190075Sobrien mark_read, 62169689Skan mark_write, 63169689Skan /* mark_access is for marking the destination regs in 64169689Skan REG_FRAME_RELATED_EXPR notes (as if they were read) so that the 65169689Skan note is updated properly. */ 66169689Skan mark_access 6790075Sobrien}; 6890075Sobrien 6990075Sobrienstatic const char * const scan_actions_name[] = 7090075Sobrien{ 7190075Sobrien "terminate_all_read", 7290075Sobrien "terminate_overlapping_read", 7390075Sobrien "terminate_write", 7490075Sobrien "terminate_dead", 7590075Sobrien "mark_read", 76169689Skan "mark_write", 77169689Skan "mark_access" 7890075Sobrien}; 7990075Sobrien 8090075Sobrienstatic struct obstack rename_obstack; 8190075Sobrien 82132718Skanstatic void do_replace (struct du_chain *, int); 83132718Skanstatic void scan_rtx_reg (rtx, rtx *, enum reg_class, 84132718Skan enum scan_actions, enum op_type, int); 85132718Skanstatic void scan_rtx_address (rtx, rtx *, enum reg_class, 86132718Skan enum scan_actions, enum machine_mode); 87132718Skanstatic void scan_rtx (rtx, rtx *, enum reg_class, enum scan_actions, 88132718Skan enum op_type, int); 89132718Skanstatic struct du_chain *build_def_use (basic_block); 90132718Skanstatic void dump_def_use_chain (struct du_chain *); 91132718Skanstatic void note_sets (rtx, rtx, void *); 92132718Skanstatic void clear_dead_regs (HARD_REG_SET *, enum machine_mode, rtx); 93132718Skanstatic void merge_overlapping_regs (basic_block, HARD_REG_SET *, 94132718Skan struct du_chain *); 9590075Sobrien 9690075Sobrien/* Called through note_stores from update_life. Find sets of registers, and 9790075Sobrien record them in *DATA (which is actually a HARD_REG_SET *). */ 9890075Sobrien 9990075Sobrienstatic void 100132718Skannote_sets (rtx x, rtx set ATTRIBUTE_UNUSED, void *data) 10190075Sobrien{ 10290075Sobrien HARD_REG_SET *pset = (HARD_REG_SET *) data; 10390075Sobrien unsigned int regno; 10490075Sobrien int nregs; 105146895Skan 106146895Skan if (GET_CODE (x) == SUBREG) 107146895Skan x = SUBREG_REG (x); 108169689Skan if (!REG_P (x)) 10990075Sobrien return; 11090075Sobrien regno = REGNO (x); 111169689Skan nregs = hard_regno_nregs[regno][GET_MODE (x)]; 11290075Sobrien 11390075Sobrien /* There must not be pseudos at this point. */ 114169689Skan gcc_assert (regno + nregs <= FIRST_PSEUDO_REGISTER); 11590075Sobrien 11690075Sobrien while (nregs-- > 0) 11790075Sobrien SET_HARD_REG_BIT (*pset, regno + nregs); 11890075Sobrien} 11990075Sobrien 12090075Sobrien/* Clear all registers from *PSET for which a note of kind KIND can be found 12190075Sobrien in the list NOTES. */ 12290075Sobrien 12390075Sobrienstatic void 124132718Skanclear_dead_regs (HARD_REG_SET *pset, enum machine_mode kind, rtx notes) 12590075Sobrien{ 12690075Sobrien rtx note; 12790075Sobrien for (note = notes; note; note = XEXP (note, 1)) 12890075Sobrien if (REG_NOTE_KIND (note) == kind && REG_P (XEXP (note, 0))) 12990075Sobrien { 13090075Sobrien rtx reg = XEXP (note, 0); 13190075Sobrien unsigned int regno = REGNO (reg); 132169689Skan int nregs = hard_regno_nregs[regno][GET_MODE (reg)]; 13390075Sobrien 13490075Sobrien /* There must not be pseudos at this point. */ 135169689Skan gcc_assert (regno + nregs <= FIRST_PSEUDO_REGISTER); 13690075Sobrien 13790075Sobrien while (nregs-- > 0) 13890075Sobrien CLEAR_HARD_REG_BIT (*pset, regno + nregs); 13990075Sobrien } 14090075Sobrien} 14190075Sobrien 14290075Sobrien/* For a def-use chain CHAIN in basic block B, find which registers overlap 14390075Sobrien its lifetime and set the corresponding bits in *PSET. */ 14490075Sobrien 14590075Sobrienstatic void 146132718Skanmerge_overlapping_regs (basic_block b, HARD_REG_SET *pset, 147132718Skan struct du_chain *chain) 14890075Sobrien{ 14990075Sobrien struct du_chain *t = chain; 15090075Sobrien rtx insn; 15190075Sobrien HARD_REG_SET live; 15290075Sobrien 153169689Skan REG_SET_TO_HARD_REG_SET (live, b->il.rtl->global_live_at_start); 154132718Skan insn = BB_HEAD (b); 15590075Sobrien while (t) 15690075Sobrien { 15790075Sobrien /* Search forward until the next reference to the register to be 15890075Sobrien renamed. */ 15990075Sobrien while (insn != t->insn) 16090075Sobrien { 16190075Sobrien if (INSN_P (insn)) 16290075Sobrien { 16390075Sobrien clear_dead_regs (&live, REG_DEAD, REG_NOTES (insn)); 16490075Sobrien note_stores (PATTERN (insn), note_sets, (void *) &live); 16590075Sobrien /* Only record currently live regs if we are inside the 16690075Sobrien reg's live range. */ 16790075Sobrien if (t != chain) 16890075Sobrien IOR_HARD_REG_SET (*pset, live); 169117395Skan clear_dead_regs (&live, REG_UNUSED, REG_NOTES (insn)); 17090075Sobrien } 17190075Sobrien insn = NEXT_INSN (insn); 17290075Sobrien } 17390075Sobrien 17490075Sobrien IOR_HARD_REG_SET (*pset, live); 17590075Sobrien 17690075Sobrien /* For the last reference, also merge in all registers set in the 17790075Sobrien same insn. 17890075Sobrien @@@ We only have take earlyclobbered sets into account. */ 17990075Sobrien if (! t->next_use) 18090075Sobrien note_stores (PATTERN (insn), note_sets, (void *) pset); 18190075Sobrien 18290075Sobrien t = t->next_use; 18390075Sobrien } 18490075Sobrien} 18590075Sobrien 18690075Sobrien/* Perform register renaming on the current function. */ 18790075Sobrien 188169689Skanstatic void 189132718Skanregrename_optimize (void) 19090075Sobrien{ 19190075Sobrien int tick[FIRST_PSEUDO_REGISTER]; 19290075Sobrien int this_tick = 0; 193117395Skan basic_block bb; 19490075Sobrien char *first_obj; 19590075Sobrien 19690075Sobrien memset (tick, 0, sizeof tick); 19790075Sobrien 19890075Sobrien gcc_obstack_init (&rename_obstack); 199132718Skan first_obj = obstack_alloc (&rename_obstack, 0); 20090075Sobrien 201117395Skan FOR_EACH_BB (bb) 20290075Sobrien { 20390075Sobrien struct du_chain *all_chains = 0; 20490075Sobrien HARD_REG_SET unavailable; 20590075Sobrien HARD_REG_SET regs_seen; 20690075Sobrien 20790075Sobrien CLEAR_HARD_REG_SET (unavailable); 20890075Sobrien 209169689Skan if (dump_file) 210169689Skan fprintf (dump_file, "\nBasic block %d:\n", bb->index); 21190075Sobrien 21290075Sobrien all_chains = build_def_use (bb); 21390075Sobrien 214169689Skan if (dump_file) 21590075Sobrien dump_def_use_chain (all_chains); 21690075Sobrien 21790075Sobrien CLEAR_HARD_REG_SET (unavailable); 21890075Sobrien /* Don't clobber traceback for noreturn functions. */ 21990075Sobrien if (frame_pointer_needed) 22090075Sobrien { 22190075Sobrien int i; 222117395Skan 223169689Skan for (i = hard_regno_nregs[FRAME_POINTER_REGNUM][Pmode]; i--;) 22490075Sobrien SET_HARD_REG_BIT (unavailable, FRAME_POINTER_REGNUM + i); 225117395Skan 22690075Sobrien#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM 227169689Skan for (i = hard_regno_nregs[HARD_FRAME_POINTER_REGNUM][Pmode]; i--;) 22890075Sobrien SET_HARD_REG_BIT (unavailable, HARD_FRAME_POINTER_REGNUM + i); 22990075Sobrien#endif 23090075Sobrien } 23190075Sobrien 23290075Sobrien CLEAR_HARD_REG_SET (regs_seen); 23390075Sobrien while (all_chains) 23490075Sobrien { 235132718Skan int new_reg, best_new_reg; 23690075Sobrien int n_uses; 23790075Sobrien struct du_chain *this = all_chains; 23890075Sobrien struct du_chain *tmp, *last; 23990075Sobrien HARD_REG_SET this_unavailable; 24090075Sobrien int reg = REGNO (*this->loc); 24190075Sobrien int i; 24290075Sobrien 24390075Sobrien all_chains = this->next_chain; 244117395Skan 245132718Skan best_new_reg = reg; 246132718Skan 24790075Sobrien#if 0 /* This just disables optimization opportunities. */ 24890075Sobrien /* Only rename once we've seen the reg more than once. */ 24990075Sobrien if (! TEST_HARD_REG_BIT (regs_seen, reg)) 25090075Sobrien { 25190075Sobrien SET_HARD_REG_BIT (regs_seen, reg); 25290075Sobrien continue; 25390075Sobrien } 25490075Sobrien#endif 25590075Sobrien 25690075Sobrien if (fixed_regs[reg] || global_regs[reg] 25790075Sobrien#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM 25890075Sobrien || (frame_pointer_needed && reg == HARD_FRAME_POINTER_REGNUM) 25990075Sobrien#else 26090075Sobrien || (frame_pointer_needed && reg == FRAME_POINTER_REGNUM) 26190075Sobrien#endif 26290075Sobrien ) 26390075Sobrien continue; 26490075Sobrien 26590075Sobrien COPY_HARD_REG_SET (this_unavailable, unavailable); 26690075Sobrien 26790075Sobrien /* Find last entry on chain (which has the need_caller_save bit), 26890075Sobrien count number of uses, and narrow the set of registers we can 26990075Sobrien use for renaming. */ 27090075Sobrien n_uses = 0; 27190075Sobrien for (last = this; last->next_use; last = last->next_use) 27290075Sobrien { 27390075Sobrien n_uses++; 27490075Sobrien IOR_COMPL_HARD_REG_SET (this_unavailable, 275169689Skan reg_class_contents[last->cl]); 27690075Sobrien } 27790075Sobrien if (n_uses < 1) 27890075Sobrien continue; 27990075Sobrien 28090075Sobrien IOR_COMPL_HARD_REG_SET (this_unavailable, 281169689Skan reg_class_contents[last->cl]); 28290075Sobrien 28390075Sobrien if (this->need_caller_save_reg) 28490075Sobrien IOR_HARD_REG_SET (this_unavailable, call_used_reg_set); 28590075Sobrien 28690075Sobrien merge_overlapping_regs (bb, &this_unavailable, this); 28790075Sobrien 28890075Sobrien /* Now potential_regs is a reasonable approximation, let's 28990075Sobrien have a closer look at each register still in there. */ 29090075Sobrien for (new_reg = 0; new_reg < FIRST_PSEUDO_REGISTER; new_reg++) 29190075Sobrien { 292169689Skan int nregs = hard_regno_nregs[new_reg][GET_MODE (*this->loc)]; 29390075Sobrien 29490075Sobrien for (i = nregs - 1; i >= 0; --i) 29590075Sobrien if (TEST_HARD_REG_BIT (this_unavailable, new_reg + i) 29690075Sobrien || fixed_regs[new_reg + i] 29790075Sobrien || global_regs[new_reg + i] 29890075Sobrien /* Can't use regs which aren't saved by the prologue. */ 29990075Sobrien || (! regs_ever_live[new_reg + i] 30090075Sobrien && ! call_used_regs[new_reg + i]) 30190075Sobrien#ifdef LEAF_REGISTERS 302117395Skan /* We can't use a non-leaf register if we're in a 30390075Sobrien leaf function. */ 304117395Skan || (current_function_is_leaf 30590075Sobrien && !LEAF_REGISTERS[new_reg + i]) 30690075Sobrien#endif 30790075Sobrien#ifdef HARD_REGNO_RENAME_OK 30890075Sobrien || ! HARD_REGNO_RENAME_OK (reg + i, new_reg + i) 30990075Sobrien#endif 31090075Sobrien ) 31190075Sobrien break; 31290075Sobrien if (i >= 0) 31390075Sobrien continue; 31490075Sobrien 31590075Sobrien /* See whether it accepts all modes that occur in 31690075Sobrien definition and uses. */ 31790075Sobrien for (tmp = this; tmp; tmp = tmp->next_use) 31896263Sobrien if (! HARD_REGNO_MODE_OK (new_reg, GET_MODE (*tmp->loc)) 31996263Sobrien || (tmp->need_caller_save_reg 32096263Sobrien && ! (HARD_REGNO_CALL_PART_CLOBBERED 32196263Sobrien (reg, GET_MODE (*tmp->loc))) 32296263Sobrien && (HARD_REGNO_CALL_PART_CLOBBERED 32396263Sobrien (new_reg, GET_MODE (*tmp->loc))))) 32490075Sobrien break; 32590075Sobrien if (! tmp) 32690075Sobrien { 327132718Skan if (tick[best_new_reg] > tick[new_reg]) 32890075Sobrien best_new_reg = new_reg; 32990075Sobrien } 33090075Sobrien } 33190075Sobrien 332169689Skan if (dump_file) 33390075Sobrien { 334169689Skan fprintf (dump_file, "Register %s in insn %d", 33590075Sobrien reg_names[reg], INSN_UID (last->insn)); 33690075Sobrien if (last->need_caller_save_reg) 337169689Skan fprintf (dump_file, " crosses a call"); 338117395Skan } 33990075Sobrien 340132718Skan if (best_new_reg == reg) 34190075Sobrien { 342132718Skan tick[reg] = ++this_tick; 343169689Skan if (dump_file) 344169689Skan fprintf (dump_file, "; no available better choice\n"); 34590075Sobrien continue; 34690075Sobrien } 34790075Sobrien 34890075Sobrien do_replace (this, best_new_reg); 349132718Skan tick[best_new_reg] = ++this_tick; 350169689Skan regs_ever_live[best_new_reg] = 1; 35190075Sobrien 352169689Skan if (dump_file) 353169689Skan fprintf (dump_file, ", renamed as %s\n", reg_names[best_new_reg]); 35490075Sobrien } 35590075Sobrien 35690075Sobrien obstack_free (&rename_obstack, first_obj); 35790075Sobrien } 35890075Sobrien 35990075Sobrien obstack_free (&rename_obstack, NULL); 36090075Sobrien 361169689Skan if (dump_file) 362169689Skan fputc ('\n', dump_file); 36390075Sobrien 36490075Sobrien count_or_remove_death_notes (NULL, 1); 36590075Sobrien update_life_info (NULL, UPDATE_LIFE_LOCAL, 366169689Skan PROP_DEATH_NOTES); 36790075Sobrien} 36890075Sobrien 36990075Sobrienstatic void 370132718Skando_replace (struct du_chain *chain, int reg) 37190075Sobrien{ 37290075Sobrien while (chain) 37390075Sobrien { 37490075Sobrien unsigned int regno = ORIGINAL_REGNO (*chain->loc); 375132718Skan struct reg_attrs * attr = REG_ATTRS (*chain->loc); 376132718Skan 37790075Sobrien *chain->loc = gen_raw_REG (GET_MODE (*chain->loc), reg); 37890075Sobrien if (regno >= FIRST_PSEUDO_REGISTER) 37990075Sobrien ORIGINAL_REGNO (*chain->loc) = regno; 380132718Skan REG_ATTRS (*chain->loc) = attr; 38190075Sobrien chain = chain->next_use; 38290075Sobrien } 38390075Sobrien} 38490075Sobrien 38590075Sobrien 38690075Sobrienstatic struct du_chain *open_chains; 38790075Sobrienstatic struct du_chain *closed_chains; 38890075Sobrien 38990075Sobrienstatic void 390169689Skanscan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl, 391132718Skan enum scan_actions action, enum op_type type, int earlyclobber) 39290075Sobrien{ 39390075Sobrien struct du_chain **p; 39490075Sobrien rtx x = *loc; 39590075Sobrien enum machine_mode mode = GET_MODE (x); 39690075Sobrien int this_regno = REGNO (x); 397169689Skan int this_nregs = hard_regno_nregs[this_regno][mode]; 39890075Sobrien 39990075Sobrien if (action == mark_write) 40090075Sobrien { 40190075Sobrien if (type == OP_OUT) 40290075Sobrien { 403132718Skan struct du_chain *this 404132718Skan = obstack_alloc (&rename_obstack, sizeof (struct du_chain)); 40590075Sobrien this->next_use = 0; 40690075Sobrien this->next_chain = open_chains; 40790075Sobrien this->loc = loc; 40890075Sobrien this->insn = insn; 409169689Skan this->cl = cl; 41090075Sobrien this->need_caller_save_reg = 0; 41190075Sobrien this->earlyclobber = earlyclobber; 41290075Sobrien open_chains = this; 41390075Sobrien } 41490075Sobrien return; 41590075Sobrien } 41690075Sobrien 417169689Skan if ((type == OP_OUT) != (action == terminate_write || action == mark_access)) 41890075Sobrien return; 41990075Sobrien 42090075Sobrien for (p = &open_chains; *p;) 42190075Sobrien { 42290075Sobrien struct du_chain *this = *p; 42390075Sobrien 42490075Sobrien /* Check if the chain has been terminated if it has then skip to 42590075Sobrien the next chain. 42690075Sobrien 42790075Sobrien This can happen when we've already appended the location to 42890075Sobrien the chain in Step 3, but are trying to hide in-out operands 42990075Sobrien from terminate_write in Step 5. */ 43090075Sobrien 43190075Sobrien if (*this->loc == cc0_rtx) 43290075Sobrien p = &this->next_chain; 43390075Sobrien else 434117395Skan { 43590075Sobrien int regno = REGNO (*this->loc); 436169689Skan int nregs = hard_regno_nregs[regno][GET_MODE (*this->loc)]; 43790075Sobrien int exact_match = (regno == this_regno && nregs == this_nregs); 43890075Sobrien 43990075Sobrien if (regno + nregs <= this_regno 44090075Sobrien || this_regno + this_nregs <= regno) 44190075Sobrien { 44290075Sobrien p = &this->next_chain; 44390075Sobrien continue; 44490075Sobrien } 44590075Sobrien 446169689Skan if (action == mark_read || action == mark_access) 44790075Sobrien { 448169689Skan gcc_assert (exact_match); 44990075Sobrien 450117395Skan /* ??? Class NO_REGS can happen if the md file makes use of 45190075Sobrien EXTRA_CONSTRAINTS to match registers. Which is arguably 45290075Sobrien wrong, but there we are. Since we know not what this may 45390075Sobrien be replaced with, terminate the chain. */ 454169689Skan if (cl != NO_REGS) 45590075Sobrien { 456132718Skan this = obstack_alloc (&rename_obstack, sizeof (struct du_chain)); 45790075Sobrien this->next_use = 0; 45890075Sobrien this->next_chain = (*p)->next_chain; 45990075Sobrien this->loc = loc; 46090075Sobrien this->insn = insn; 461169689Skan this->cl = cl; 46290075Sobrien this->need_caller_save_reg = 0; 46390075Sobrien while (*p) 46490075Sobrien p = &(*p)->next_use; 46590075Sobrien *p = this; 46690075Sobrien return; 46790075Sobrien } 46890075Sobrien } 46990075Sobrien 47090075Sobrien if (action != terminate_overlapping_read || ! exact_match) 47190075Sobrien { 47290075Sobrien struct du_chain *next = this->next_chain; 47390075Sobrien 47490075Sobrien /* Whether the terminated chain can be used for renaming 47590075Sobrien depends on the action and this being an exact match. 47690075Sobrien In either case, we remove this element from open_chains. */ 47790075Sobrien 47890075Sobrien if ((action == terminate_dead || action == terminate_write) 47990075Sobrien && exact_match) 48090075Sobrien { 48190075Sobrien this->next_chain = closed_chains; 48290075Sobrien closed_chains = this; 483169689Skan if (dump_file) 484169689Skan fprintf (dump_file, 48590075Sobrien "Closing chain %s at insn %d (%s)\n", 48690075Sobrien reg_names[REGNO (*this->loc)], INSN_UID (insn), 48790075Sobrien scan_actions_name[(int) action]); 48890075Sobrien } 48990075Sobrien else 49090075Sobrien { 491169689Skan if (dump_file) 492169689Skan fprintf (dump_file, 49390075Sobrien "Discarding chain %s at insn %d (%s)\n", 49490075Sobrien reg_names[REGNO (*this->loc)], INSN_UID (insn), 49590075Sobrien scan_actions_name[(int) action]); 49690075Sobrien } 49790075Sobrien *p = next; 49890075Sobrien } 49990075Sobrien else 50090075Sobrien p = &this->next_chain; 50190075Sobrien } 50290075Sobrien } 50390075Sobrien} 50490075Sobrien 505169689Skan/* Adapted from find_reloads_address_1. CL is INDEX_REG_CLASS or 50690075Sobrien BASE_REG_CLASS depending on how the register is being considered. */ 50790075Sobrien 50890075Sobrienstatic void 509169689Skanscan_rtx_address (rtx insn, rtx *loc, enum reg_class cl, 510132718Skan enum scan_actions action, enum machine_mode mode) 51190075Sobrien{ 51290075Sobrien rtx x = *loc; 51390075Sobrien RTX_CODE code = GET_CODE (x); 51490075Sobrien const char *fmt; 51590075Sobrien int i, j; 51690075Sobrien 517169689Skan if (action == mark_write || action == mark_access) 51890075Sobrien return; 51990075Sobrien 52090075Sobrien switch (code) 52190075Sobrien { 52290075Sobrien case PLUS: 52390075Sobrien { 52490075Sobrien rtx orig_op0 = XEXP (x, 0); 52590075Sobrien rtx orig_op1 = XEXP (x, 1); 52690075Sobrien RTX_CODE code0 = GET_CODE (orig_op0); 52790075Sobrien RTX_CODE code1 = GET_CODE (orig_op1); 52890075Sobrien rtx op0 = orig_op0; 52990075Sobrien rtx op1 = orig_op1; 53090075Sobrien rtx *locI = NULL; 53190075Sobrien rtx *locB = NULL; 532169689Skan enum rtx_code index_code = SCRATCH; 53390075Sobrien 53490075Sobrien if (GET_CODE (op0) == SUBREG) 53590075Sobrien { 53690075Sobrien op0 = SUBREG_REG (op0); 53790075Sobrien code0 = GET_CODE (op0); 53890075Sobrien } 53990075Sobrien 54090075Sobrien if (GET_CODE (op1) == SUBREG) 54190075Sobrien { 54290075Sobrien op1 = SUBREG_REG (op1); 54390075Sobrien code1 = GET_CODE (op1); 54490075Sobrien } 54590075Sobrien 54690075Sobrien if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE 54790075Sobrien || code0 == ZERO_EXTEND || code1 == MEM) 54890075Sobrien { 54990075Sobrien locI = &XEXP (x, 0); 55090075Sobrien locB = &XEXP (x, 1); 551169689Skan index_code = GET_CODE (*locI); 55290075Sobrien } 55390075Sobrien else if (code1 == MULT || code1 == SIGN_EXTEND || code1 == TRUNCATE 55490075Sobrien || code1 == ZERO_EXTEND || code0 == MEM) 55590075Sobrien { 55690075Sobrien locI = &XEXP (x, 1); 55790075Sobrien locB = &XEXP (x, 0); 558169689Skan index_code = GET_CODE (*locI); 55990075Sobrien } 56090075Sobrien else if (code0 == CONST_INT || code0 == CONST 56190075Sobrien || code0 == SYMBOL_REF || code0 == LABEL_REF) 562169689Skan { 563169689Skan locB = &XEXP (x, 1); 564169689Skan index_code = GET_CODE (XEXP (x, 0)); 565169689Skan } 56690075Sobrien else if (code1 == CONST_INT || code1 == CONST 56790075Sobrien || code1 == SYMBOL_REF || code1 == LABEL_REF) 568169689Skan { 569169689Skan locB = &XEXP (x, 0); 570169689Skan index_code = GET_CODE (XEXP (x, 1)); 571169689Skan } 57290075Sobrien else if (code0 == REG && code1 == REG) 57390075Sobrien { 57490075Sobrien int index_op; 575169689Skan unsigned regno0 = REGNO (op0), regno1 = REGNO (op1); 57690075Sobrien 577169689Skan if (REGNO_OK_FOR_INDEX_P (regno0) 578169689Skan && regno_ok_for_base_p (regno1, mode, PLUS, REG)) 57990075Sobrien index_op = 0; 580169689Skan else if (REGNO_OK_FOR_INDEX_P (regno1) 581169689Skan && regno_ok_for_base_p (regno0, mode, PLUS, REG)) 58290075Sobrien index_op = 1; 583169689Skan else if (regno_ok_for_base_p (regno1, mode, PLUS, REG)) 58490075Sobrien index_op = 0; 585169689Skan else if (regno_ok_for_base_p (regno0, mode, PLUS, REG)) 58690075Sobrien index_op = 1; 587169689Skan else if (REGNO_OK_FOR_INDEX_P (regno1)) 58890075Sobrien index_op = 1; 58990075Sobrien else 59090075Sobrien index_op = 0; 59190075Sobrien 59290075Sobrien locI = &XEXP (x, index_op); 59390075Sobrien locB = &XEXP (x, !index_op); 594169689Skan index_code = GET_CODE (*locI); 59590075Sobrien } 59690075Sobrien else if (code0 == REG) 59790075Sobrien { 59890075Sobrien locI = &XEXP (x, 0); 59990075Sobrien locB = &XEXP (x, 1); 600169689Skan index_code = GET_CODE (*locI); 60190075Sobrien } 60290075Sobrien else if (code1 == REG) 60390075Sobrien { 60490075Sobrien locI = &XEXP (x, 1); 60590075Sobrien locB = &XEXP (x, 0); 606169689Skan index_code = GET_CODE (*locI); 60790075Sobrien } 60890075Sobrien 60990075Sobrien if (locI) 61090075Sobrien scan_rtx_address (insn, locI, INDEX_REG_CLASS, action, mode); 61190075Sobrien if (locB) 612169689Skan scan_rtx_address (insn, locB, base_reg_class (mode, PLUS, index_code), 613169689Skan action, mode); 614169689Skan 61590075Sobrien return; 61690075Sobrien } 61790075Sobrien 61890075Sobrien case POST_INC: 61990075Sobrien case POST_DEC: 62090075Sobrien case POST_MODIFY: 62190075Sobrien case PRE_INC: 62290075Sobrien case PRE_DEC: 62390075Sobrien case PRE_MODIFY: 62490075Sobrien#ifndef AUTO_INC_DEC 62590075Sobrien /* If the target doesn't claim to handle autoinc, this must be 62690075Sobrien something special, like a stack push. Kill this chain. */ 62790075Sobrien action = terminate_all_read; 62890075Sobrien#endif 62990075Sobrien break; 63090075Sobrien 63190075Sobrien case MEM: 63290075Sobrien scan_rtx_address (insn, &XEXP (x, 0), 633169689Skan base_reg_class (GET_MODE (x), MEM, SCRATCH), action, 63490075Sobrien GET_MODE (x)); 63590075Sobrien return; 63690075Sobrien 63790075Sobrien case REG: 638169689Skan scan_rtx_reg (insn, loc, cl, action, OP_IN, 0); 63990075Sobrien return; 64090075Sobrien 64190075Sobrien default: 64290075Sobrien break; 64390075Sobrien } 64490075Sobrien 64590075Sobrien fmt = GET_RTX_FORMAT (code); 64690075Sobrien for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) 64790075Sobrien { 64890075Sobrien if (fmt[i] == 'e') 649169689Skan scan_rtx_address (insn, &XEXP (x, i), cl, action, mode); 65090075Sobrien else if (fmt[i] == 'E') 65190075Sobrien for (j = XVECLEN (x, i) - 1; j >= 0; j--) 652169689Skan scan_rtx_address (insn, &XVECEXP (x, i, j), cl, action, mode); 65390075Sobrien } 65490075Sobrien} 65590075Sobrien 65690075Sobrienstatic void 657169689Skanscan_rtx (rtx insn, rtx *loc, enum reg_class cl, 658132718Skan enum scan_actions action, enum op_type type, int earlyclobber) 65990075Sobrien{ 66090075Sobrien const char *fmt; 66190075Sobrien rtx x = *loc; 66290075Sobrien enum rtx_code code = GET_CODE (x); 66390075Sobrien int i, j; 66490075Sobrien 66590075Sobrien code = GET_CODE (x); 66690075Sobrien switch (code) 66790075Sobrien { 66890075Sobrien case CONST: 66990075Sobrien case CONST_INT: 67090075Sobrien case CONST_DOUBLE: 67196263Sobrien case CONST_VECTOR: 67290075Sobrien case SYMBOL_REF: 67390075Sobrien case LABEL_REF: 67490075Sobrien case CC0: 67590075Sobrien case PC: 67690075Sobrien return; 67790075Sobrien 67890075Sobrien case REG: 679169689Skan scan_rtx_reg (insn, loc, cl, action, type, earlyclobber); 68090075Sobrien return; 68190075Sobrien 68290075Sobrien case MEM: 68390075Sobrien scan_rtx_address (insn, &XEXP (x, 0), 684169689Skan base_reg_class (GET_MODE (x), MEM, SCRATCH), action, 68590075Sobrien GET_MODE (x)); 68690075Sobrien return; 68790075Sobrien 68890075Sobrien case SET: 689169689Skan scan_rtx (insn, &SET_SRC (x), cl, action, OP_IN, 0); 690169689Skan scan_rtx (insn, &SET_DEST (x), cl, action, 691161651Skan GET_CODE (PATTERN (insn)) == COND_EXEC ? OP_INOUT : OP_OUT, 0); 69290075Sobrien return; 69390075Sobrien 69490075Sobrien case STRICT_LOW_PART: 695169689Skan scan_rtx (insn, &XEXP (x, 0), cl, action, OP_INOUT, earlyclobber); 69690075Sobrien return; 69790075Sobrien 69890075Sobrien case ZERO_EXTRACT: 699117395Skan case SIGN_EXTRACT: 700169689Skan scan_rtx (insn, &XEXP (x, 0), cl, action, 70190075Sobrien type == OP_IN ? OP_IN : OP_INOUT, earlyclobber); 702169689Skan scan_rtx (insn, &XEXP (x, 1), cl, action, OP_IN, 0); 703169689Skan scan_rtx (insn, &XEXP (x, 2), cl, action, OP_IN, 0); 70490075Sobrien return; 70590075Sobrien 70690075Sobrien case POST_INC: 70790075Sobrien case PRE_INC: 70890075Sobrien case POST_DEC: 70990075Sobrien case PRE_DEC: 71090075Sobrien case POST_MODIFY: 71190075Sobrien case PRE_MODIFY: 71290075Sobrien /* Should only happen inside MEM. */ 713169689Skan gcc_unreachable (); 71490075Sobrien 71590075Sobrien case CLOBBER: 716169689Skan scan_rtx (insn, &SET_DEST (x), cl, action, 717169689Skan GET_CODE (PATTERN (insn)) == COND_EXEC ? OP_INOUT : OP_OUT, 0); 71890075Sobrien return; 71990075Sobrien 72090075Sobrien case EXPR_LIST: 721169689Skan scan_rtx (insn, &XEXP (x, 0), cl, action, type, 0); 72290075Sobrien if (XEXP (x, 1)) 723169689Skan scan_rtx (insn, &XEXP (x, 1), cl, action, type, 0); 72490075Sobrien return; 72590075Sobrien 72690075Sobrien default: 72790075Sobrien break; 72890075Sobrien } 72990075Sobrien 73090075Sobrien fmt = GET_RTX_FORMAT (code); 73190075Sobrien for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) 73290075Sobrien { 73390075Sobrien if (fmt[i] == 'e') 734169689Skan scan_rtx (insn, &XEXP (x, i), cl, action, type, 0); 73590075Sobrien else if (fmt[i] == 'E') 73690075Sobrien for (j = XVECLEN (x, i) - 1; j >= 0; j--) 737169689Skan scan_rtx (insn, &XVECEXP (x, i, j), cl, action, type, 0); 73890075Sobrien } 73990075Sobrien} 74090075Sobrien 741117395Skan/* Build def/use chain. */ 74290075Sobrien 74390075Sobrienstatic struct du_chain * 744132718Skanbuild_def_use (basic_block bb) 74590075Sobrien{ 74690075Sobrien rtx insn; 74790075Sobrien 74890075Sobrien open_chains = closed_chains = NULL; 74990075Sobrien 750132718Skan for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn)) 75190075Sobrien { 75290075Sobrien if (INSN_P (insn)) 75390075Sobrien { 75490075Sobrien int n_ops; 75590075Sobrien rtx note; 75690075Sobrien rtx old_operands[MAX_RECOG_OPERANDS]; 75790075Sobrien rtx old_dups[MAX_DUP_OPERANDS]; 75896263Sobrien int i, icode; 75990075Sobrien int alt; 76090075Sobrien int predicated; 76190075Sobrien 76290075Sobrien /* Process the insn, determining its effect on the def-use 76390075Sobrien chains. We perform the following steps with the register 76490075Sobrien references in the insn: 76590075Sobrien (1) Any read that overlaps an open chain, but doesn't exactly 76690075Sobrien match, causes that chain to be closed. We can't deal 76790075Sobrien with overlaps yet. 76890075Sobrien (2) Any read outside an operand causes any chain it overlaps 76990075Sobrien with to be closed, since we can't replace it. 77090075Sobrien (3) Any read inside an operand is added if there's already 77190075Sobrien an open chain for it. 77290075Sobrien (4) For any REG_DEAD note we find, close open chains that 77390075Sobrien overlap it. 77490075Sobrien (5) For any write we find, close open chains that overlap it. 77590075Sobrien (6) For any write we find in an operand, make a new chain. 77690075Sobrien (7) For any REG_UNUSED, close any chains we just opened. */ 77790075Sobrien 77896263Sobrien icode = recog_memoized (insn); 77990075Sobrien extract_insn (insn); 780117395Skan if (! constrain_operands (1)) 781117395Skan fatal_insn_not_found (insn); 78290075Sobrien preprocess_constraints (); 78390075Sobrien alt = which_alternative; 78490075Sobrien n_ops = recog_data.n_operands; 78590075Sobrien 78690075Sobrien /* Simplify the code below by rewriting things to reflect 78790075Sobrien matching constraints. Also promote OP_OUT to OP_INOUT 78890075Sobrien in predicated instructions. */ 78990075Sobrien 79090075Sobrien predicated = GET_CODE (PATTERN (insn)) == COND_EXEC; 79190075Sobrien for (i = 0; i < n_ops; ++i) 79290075Sobrien { 79390075Sobrien int matches = recog_op_alt[i][alt].matches; 79490075Sobrien if (matches >= 0) 795169689Skan recog_op_alt[i][alt].cl = recog_op_alt[matches][alt].cl; 79690075Sobrien if (matches >= 0 || recog_op_alt[i][alt].matched >= 0 79790075Sobrien || (predicated && recog_data.operand_type[i] == OP_OUT)) 79890075Sobrien recog_data.operand_type[i] = OP_INOUT; 79990075Sobrien } 80090075Sobrien 80190075Sobrien /* Step 1: Close chains for which we have overlapping reads. */ 80290075Sobrien for (i = 0; i < n_ops; i++) 80390075Sobrien scan_rtx (insn, recog_data.operand_loc[i], 80490075Sobrien NO_REGS, terminate_overlapping_read, 80590075Sobrien recog_data.operand_type[i], 0); 80690075Sobrien 80790075Sobrien /* Step 2: Close chains for which we have reads outside operands. 808117395Skan We do this by munging all operands into CC0, and closing 80990075Sobrien everything remaining. */ 81090075Sobrien 81190075Sobrien for (i = 0; i < n_ops; i++) 81290075Sobrien { 81390075Sobrien old_operands[i] = recog_data.operand[i]; 81490075Sobrien /* Don't squash match_operator or match_parallel here, since 815117395Skan we don't know that all of the contained registers are 81690075Sobrien reachable by proper operands. */ 81790075Sobrien if (recog_data.constraints[i][0] == '\0') 81890075Sobrien continue; 81990075Sobrien *recog_data.operand_loc[i] = cc0_rtx; 82090075Sobrien } 82190075Sobrien for (i = 0; i < recog_data.n_dups; i++) 82290075Sobrien { 82396263Sobrien int dup_num = recog_data.dup_num[i]; 82496263Sobrien 82590075Sobrien old_dups[i] = *recog_data.dup_loc[i]; 82690075Sobrien *recog_data.dup_loc[i] = cc0_rtx; 82796263Sobrien 82896263Sobrien /* For match_dup of match_operator or match_parallel, share 82996263Sobrien them, so that we don't miss changes in the dup. */ 83096263Sobrien if (icode >= 0 83196263Sobrien && insn_data[icode].operand[dup_num].eliminable == 0) 83296263Sobrien old_dups[i] = recog_data.operand[dup_num]; 83390075Sobrien } 83490075Sobrien 83590075Sobrien scan_rtx (insn, &PATTERN (insn), NO_REGS, terminate_all_read, 83690075Sobrien OP_IN, 0); 83790075Sobrien 83890075Sobrien for (i = 0; i < recog_data.n_dups; i++) 83990075Sobrien *recog_data.dup_loc[i] = old_dups[i]; 84090075Sobrien for (i = 0; i < n_ops; i++) 84190075Sobrien *recog_data.operand_loc[i] = old_operands[i]; 84290075Sobrien 84390075Sobrien /* Step 2B: Can't rename function call argument registers. */ 844169689Skan if (CALL_P (insn) && CALL_INSN_FUNCTION_USAGE (insn)) 84590075Sobrien scan_rtx (insn, &CALL_INSN_FUNCTION_USAGE (insn), 84690075Sobrien NO_REGS, terminate_all_read, OP_IN, 0); 84790075Sobrien 84890075Sobrien /* Step 2C: Can't rename asm operands that were originally 84990075Sobrien hard registers. */ 85090075Sobrien if (asm_noperands (PATTERN (insn)) > 0) 85190075Sobrien for (i = 0; i < n_ops; i++) 85290075Sobrien { 85390075Sobrien rtx *loc = recog_data.operand_loc[i]; 85490075Sobrien rtx op = *loc; 85590075Sobrien 856169689Skan if (REG_P (op) 85790075Sobrien && REGNO (op) == ORIGINAL_REGNO (op) 85890075Sobrien && (recog_data.operand_type[i] == OP_IN 85990075Sobrien || recog_data.operand_type[i] == OP_INOUT)) 86090075Sobrien scan_rtx (insn, loc, NO_REGS, terminate_all_read, OP_IN, 0); 86190075Sobrien } 86290075Sobrien 86390075Sobrien /* Step 3: Append to chains for reads inside operands. */ 86490075Sobrien for (i = 0; i < n_ops + recog_data.n_dups; i++) 86590075Sobrien { 86690075Sobrien int opn = i < n_ops ? i : recog_data.dup_num[i - n_ops]; 86790075Sobrien rtx *loc = (i < n_ops 86890075Sobrien ? recog_data.operand_loc[opn] 86990075Sobrien : recog_data.dup_loc[i - n_ops]); 870169689Skan enum reg_class cl = recog_op_alt[opn][alt].cl; 87190075Sobrien enum op_type type = recog_data.operand_type[opn]; 87290075Sobrien 87390075Sobrien /* Don't scan match_operand here, since we've no reg class 87490075Sobrien information to pass down. Any operands that we could 87590075Sobrien substitute in will be represented elsewhere. */ 87690075Sobrien if (recog_data.constraints[opn][0] == '\0') 87790075Sobrien continue; 87890075Sobrien 87990075Sobrien if (recog_op_alt[opn][alt].is_address) 880169689Skan scan_rtx_address (insn, loc, cl, mark_read, VOIDmode); 88190075Sobrien else 882169689Skan scan_rtx (insn, loc, cl, mark_read, type, 0); 88390075Sobrien } 88490075Sobrien 885169689Skan /* Step 3B: Record updates for regs in REG_INC notes, and 886169689Skan source regs in REG_FRAME_RELATED_EXPR notes. */ 88790075Sobrien for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) 888169689Skan if (REG_NOTE_KIND (note) == REG_INC 889169689Skan || REG_NOTE_KIND (note) == REG_FRAME_RELATED_EXPR) 890169689Skan scan_rtx (insn, &XEXP (note, 0), ALL_REGS, mark_read, 891169689Skan OP_INOUT, 0); 89290075Sobrien 893169689Skan /* Step 4: Close chains for registers that die here. */ 894169689Skan for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) 895169689Skan if (REG_NOTE_KIND (note) == REG_DEAD) 896169689Skan scan_rtx (insn, &XEXP (note, 0), NO_REGS, terminate_dead, 897169689Skan OP_IN, 0); 898169689Skan 89990075Sobrien /* Step 4B: If this is a call, any chain live at this point 90090075Sobrien requires a caller-saved reg. */ 901169689Skan if (CALL_P (insn)) 90290075Sobrien { 90390075Sobrien struct du_chain *p; 90490075Sobrien for (p = open_chains; p; p = p->next_chain) 90590075Sobrien p->need_caller_save_reg = 1; 90690075Sobrien } 90790075Sobrien 90890075Sobrien /* Step 5: Close open chains that overlap writes. Similar to 90990075Sobrien step 2, we hide in-out operands, since we do not want to 91090075Sobrien close these chains. */ 91190075Sobrien 91290075Sobrien for (i = 0; i < n_ops; i++) 91390075Sobrien { 91490075Sobrien old_operands[i] = recog_data.operand[i]; 91590075Sobrien if (recog_data.operand_type[i] == OP_INOUT) 91690075Sobrien *recog_data.operand_loc[i] = cc0_rtx; 91790075Sobrien } 91890075Sobrien for (i = 0; i < recog_data.n_dups; i++) 91990075Sobrien { 92090075Sobrien int opn = recog_data.dup_num[i]; 92190075Sobrien old_dups[i] = *recog_data.dup_loc[i]; 92290075Sobrien if (recog_data.operand_type[opn] == OP_INOUT) 92390075Sobrien *recog_data.dup_loc[i] = cc0_rtx; 92490075Sobrien } 92590075Sobrien 92690075Sobrien scan_rtx (insn, &PATTERN (insn), NO_REGS, terminate_write, OP_IN, 0); 92790075Sobrien 92890075Sobrien for (i = 0; i < recog_data.n_dups; i++) 92990075Sobrien *recog_data.dup_loc[i] = old_dups[i]; 93090075Sobrien for (i = 0; i < n_ops; i++) 93190075Sobrien *recog_data.operand_loc[i] = old_operands[i]; 93290075Sobrien 93390075Sobrien /* Step 6: Begin new chains for writes inside operands. */ 93490075Sobrien /* ??? Many targets have output constraints on the SET_DEST 93590075Sobrien of a call insn, which is stupid, since these are certainly 93690075Sobrien ABI defined hard registers. Don't change calls at all. 93790075Sobrien Similarly take special care for asm statement that originally 93890075Sobrien referenced hard registers. */ 93990075Sobrien if (asm_noperands (PATTERN (insn)) > 0) 94090075Sobrien { 94190075Sobrien for (i = 0; i < n_ops; i++) 94290075Sobrien if (recog_data.operand_type[i] == OP_OUT) 94390075Sobrien { 94490075Sobrien rtx *loc = recog_data.operand_loc[i]; 94590075Sobrien rtx op = *loc; 946169689Skan enum reg_class cl = recog_op_alt[i][alt].cl; 94790075Sobrien 948169689Skan if (REG_P (op) 949117395Skan && REGNO (op) == ORIGINAL_REGNO (op)) 95090075Sobrien continue; 95190075Sobrien 952169689Skan scan_rtx (insn, loc, cl, mark_write, OP_OUT, 95390075Sobrien recog_op_alt[i][alt].earlyclobber); 95490075Sobrien } 95590075Sobrien } 956169689Skan else if (!CALL_P (insn)) 95790075Sobrien for (i = 0; i < n_ops + recog_data.n_dups; i++) 95890075Sobrien { 95990075Sobrien int opn = i < n_ops ? i : recog_data.dup_num[i - n_ops]; 96090075Sobrien rtx *loc = (i < n_ops 96190075Sobrien ? recog_data.operand_loc[opn] 96290075Sobrien : recog_data.dup_loc[i - n_ops]); 963169689Skan enum reg_class cl = recog_op_alt[opn][alt].cl; 96490075Sobrien 96590075Sobrien if (recog_data.operand_type[opn] == OP_OUT) 966169689Skan scan_rtx (insn, loc, cl, mark_write, OP_OUT, 96790075Sobrien recog_op_alt[opn][alt].earlyclobber); 96890075Sobrien } 96990075Sobrien 970169689Skan /* Step 6B: Record destination regs in REG_FRAME_RELATED_EXPR 971169689Skan notes for update. */ 972169689Skan for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) 973169689Skan if (REG_NOTE_KIND (note) == REG_FRAME_RELATED_EXPR) 974169689Skan scan_rtx (insn, &XEXP (note, 0), ALL_REGS, mark_access, 975169689Skan OP_INOUT, 0); 976169689Skan 97790075Sobrien /* Step 7: Close chains for registers that were never 97890075Sobrien really used here. */ 97990075Sobrien for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) 98090075Sobrien if (REG_NOTE_KIND (note) == REG_UNUSED) 98190075Sobrien scan_rtx (insn, &XEXP (note, 0), NO_REGS, terminate_dead, 98290075Sobrien OP_IN, 0); 98390075Sobrien } 984132718Skan if (insn == BB_END (bb)) 98590075Sobrien break; 98690075Sobrien } 98790075Sobrien 98890075Sobrien /* Since we close every chain when we find a REG_DEAD note, anything that 98990075Sobrien is still open lives past the basic block, so it can't be renamed. */ 99090075Sobrien return closed_chains; 99190075Sobrien} 99290075Sobrien 993169689Skan/* Dump all def/use chains in CHAINS to DUMP_FILE. They are 99490075Sobrien printed in reverse order as that's how we build them. */ 99590075Sobrien 99690075Sobrienstatic void 997132718Skandump_def_use_chain (struct du_chain *chains) 99890075Sobrien{ 99990075Sobrien while (chains) 100090075Sobrien { 100190075Sobrien struct du_chain *this = chains; 100290075Sobrien int r = REGNO (*this->loc); 1003169689Skan int nregs = hard_regno_nregs[r][GET_MODE (*this->loc)]; 1004169689Skan fprintf (dump_file, "Register %s (%d):", reg_names[r], nregs); 100590075Sobrien while (this) 100690075Sobrien { 1007169689Skan fprintf (dump_file, " %d [%s]", INSN_UID (this->insn), 1008169689Skan reg_class_names[this->cl]); 100990075Sobrien this = this->next_use; 101090075Sobrien } 1011169689Skan fprintf (dump_file, "\n"); 101290075Sobrien chains = chains->next_chain; 101390075Sobrien } 101490075Sobrien} 101590075Sobrien 101690075Sobrien/* The following code does forward propagation of hard register copies. 101790075Sobrien The object is to eliminate as many dependencies as possible, so that 101890075Sobrien we have the most scheduling freedom. As a side effect, we also clean 1019117395Skan up some silly register allocation decisions made by reload. This 102090075Sobrien code may be obsoleted by a new register allocator. */ 102190075Sobrien 102290075Sobrien/* For each register, we have a list of registers that contain the same 1023117395Skan value. The OLDEST_REGNO field points to the head of the list, and 102490075Sobrien the NEXT_REGNO field runs through the list. The MODE field indicates 102590075Sobrien what mode the data is known to be in; this field is VOIDmode when the 102690075Sobrien register is not known to contain valid data. */ 102790075Sobrien 102890075Sobrienstruct value_data_entry 102990075Sobrien{ 103090075Sobrien enum machine_mode mode; 103190075Sobrien unsigned int oldest_regno; 103290075Sobrien unsigned int next_regno; 103390075Sobrien}; 103490075Sobrien 103590075Sobrienstruct value_data 103690075Sobrien{ 103790075Sobrien struct value_data_entry e[FIRST_PSEUDO_REGISTER]; 103890075Sobrien unsigned int max_value_regs; 103990075Sobrien}; 104090075Sobrien 1041169689Skanstatic void kill_value_one_regno (unsigned, struct value_data *); 1042169689Skanstatic void kill_value_regno (unsigned, unsigned, struct value_data *); 1043132718Skanstatic void kill_value (rtx, struct value_data *); 1044132718Skanstatic void set_value_regno (unsigned, enum machine_mode, struct value_data *); 1045132718Skanstatic void init_value_data (struct value_data *); 1046132718Skanstatic void kill_clobbered_value (rtx, rtx, void *); 1047132718Skanstatic void kill_set_value (rtx, rtx, void *); 1048132718Skanstatic int kill_autoinc_value (rtx *, void *); 1049132718Skanstatic void copy_value (rtx, rtx, struct value_data *); 1050132718Skanstatic bool mode_change_ok (enum machine_mode, enum machine_mode, 1051132718Skan unsigned int); 1052132718Skanstatic rtx maybe_mode_change (enum machine_mode, enum machine_mode, 1053132718Skan enum machine_mode, unsigned int, unsigned int); 1054132718Skanstatic rtx find_oldest_value_reg (enum reg_class, rtx, struct value_data *); 1055132718Skanstatic bool replace_oldest_value_reg (rtx *, enum reg_class, rtx, 1056132718Skan struct value_data *); 1057132718Skanstatic bool replace_oldest_value_addr (rtx *, enum reg_class, 1058132718Skan enum machine_mode, rtx, 1059132718Skan struct value_data *); 1060132718Skanstatic bool replace_oldest_value_mem (rtx, rtx, struct value_data *); 1061132718Skanstatic bool copyprop_hardreg_forward_1 (basic_block, struct value_data *); 1062132718Skanextern void debug_value_data (struct value_data *); 106390075Sobrien#ifdef ENABLE_CHECKING 1064132718Skanstatic void validate_value_data (struct value_data *); 106590075Sobrien#endif 106690075Sobrien 1067169689Skan/* Kill register REGNO. This involves removing it from any value 1068169689Skan lists, and resetting the value mode to VOIDmode. This is only a 1069169689Skan helper function; it does not handle any hard registers overlapping 1070169689Skan with REGNO. */ 107190075Sobrien 107290075Sobrienstatic void 1073169689Skankill_value_one_regno (unsigned int regno, struct value_data *vd) 107490075Sobrien{ 107590075Sobrien unsigned int i, next; 107690075Sobrien 107790075Sobrien if (vd->e[regno].oldest_regno != regno) 107890075Sobrien { 107990075Sobrien for (i = vd->e[regno].oldest_regno; 108090075Sobrien vd->e[i].next_regno != regno; 108190075Sobrien i = vd->e[i].next_regno) 108290075Sobrien continue; 108390075Sobrien vd->e[i].next_regno = vd->e[regno].next_regno; 108490075Sobrien } 108590075Sobrien else if ((next = vd->e[regno].next_regno) != INVALID_REGNUM) 108690075Sobrien { 108790075Sobrien for (i = next; i != INVALID_REGNUM; i = vd->e[i].next_regno) 1088117395Skan vd->e[i].oldest_regno = next; 108990075Sobrien } 109090075Sobrien 109190075Sobrien vd->e[regno].mode = VOIDmode; 109290075Sobrien vd->e[regno].oldest_regno = regno; 109390075Sobrien vd->e[regno].next_regno = INVALID_REGNUM; 109490075Sobrien 109590075Sobrien#ifdef ENABLE_CHECKING 109690075Sobrien validate_value_data (vd); 109790075Sobrien#endif 109890075Sobrien} 109990075Sobrien 1100169689Skan/* Kill the value in register REGNO for NREGS, and any other registers 1101169689Skan whose values overlap. */ 1102169689Skan 1103169689Skanstatic void 1104169689Skankill_value_regno (unsigned int regno, unsigned int nregs, 1105169689Skan struct value_data *vd) 1106169689Skan{ 1107169689Skan unsigned int j; 1108169689Skan 1109169689Skan /* Kill the value we're told to kill. */ 1110169689Skan for (j = 0; j < nregs; ++j) 1111169689Skan kill_value_one_regno (regno + j, vd); 1112169689Skan 1113169689Skan /* Kill everything that overlapped what we're told to kill. */ 1114169689Skan if (regno < vd->max_value_regs) 1115169689Skan j = 0; 1116169689Skan else 1117169689Skan j = regno - vd->max_value_regs; 1118169689Skan for (; j < regno; ++j) 1119169689Skan { 1120169689Skan unsigned int i, n; 1121169689Skan if (vd->e[j].mode == VOIDmode) 1122169689Skan continue; 1123169689Skan n = hard_regno_nregs[j][vd->e[j].mode]; 1124169689Skan if (j + n > regno) 1125169689Skan for (i = 0; i < n; ++i) 1126169689Skan kill_value_one_regno (j + i, vd); 1127169689Skan } 1128169689Skan} 1129169689Skan 1130169689Skan/* Kill X. This is a convenience function wrapping kill_value_regno 113190075Sobrien so that we mind the mode the register is in. */ 113290075Sobrien 113390075Sobrienstatic void 1134132718Skankill_value (rtx x, struct value_data *vd) 113590075Sobrien{ 1136169689Skan rtx orig_rtx = x; 113796263Sobrien 113896263Sobrien if (GET_CODE (x) == SUBREG) 1139169689Skan { 1140169689Skan x = simplify_subreg (GET_MODE (x), SUBREG_REG (x), 1141169689Skan GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x)); 1142169689Skan if (x == NULL_RTX) 1143169689Skan x = SUBREG_REG (orig_rtx); 1144169689Skan } 114590075Sobrien if (REG_P (x)) 114690075Sobrien { 114790075Sobrien unsigned int regno = REGNO (x); 1148169689Skan unsigned int n = hard_regno_nregs[regno][GET_MODE (x)]; 114990075Sobrien 1150169689Skan kill_value_regno (regno, n, vd); 115190075Sobrien } 115290075Sobrien} 115390075Sobrien 115490075Sobrien/* Remember that REGNO is valid in MODE. */ 115590075Sobrien 115690075Sobrienstatic void 1157132718Skanset_value_regno (unsigned int regno, enum machine_mode mode, 1158132718Skan struct value_data *vd) 115990075Sobrien{ 116090075Sobrien unsigned int nregs; 116190075Sobrien 116290075Sobrien vd->e[regno].mode = mode; 116390075Sobrien 1164169689Skan nregs = hard_regno_nregs[regno][mode]; 116590075Sobrien if (nregs > vd->max_value_regs) 116690075Sobrien vd->max_value_regs = nregs; 116790075Sobrien} 116890075Sobrien 116990075Sobrien/* Initialize VD such that there are no known relationships between regs. */ 117090075Sobrien 117190075Sobrienstatic void 1172132718Skaninit_value_data (struct value_data *vd) 117390075Sobrien{ 117490075Sobrien int i; 117590075Sobrien for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i) 117690075Sobrien { 117790075Sobrien vd->e[i].mode = VOIDmode; 117890075Sobrien vd->e[i].oldest_regno = i; 117990075Sobrien vd->e[i].next_regno = INVALID_REGNUM; 118090075Sobrien } 118190075Sobrien vd->max_value_regs = 0; 118290075Sobrien} 118390075Sobrien 118490075Sobrien/* Called through note_stores. If X is clobbered, kill its value. */ 118590075Sobrien 118690075Sobrienstatic void 1187132718Skankill_clobbered_value (rtx x, rtx set, void *data) 118890075Sobrien{ 118990075Sobrien struct value_data *vd = data; 119090075Sobrien if (GET_CODE (set) == CLOBBER) 119190075Sobrien kill_value (x, vd); 119290075Sobrien} 119390075Sobrien 1194117395Skan/* Called through note_stores. If X is set, not clobbered, kill its 119590075Sobrien current value and install it as the root of its own value list. */ 119690075Sobrien 119790075Sobrienstatic void 1198132718Skankill_set_value (rtx x, rtx set, void *data) 119990075Sobrien{ 120090075Sobrien struct value_data *vd = data; 120196263Sobrien if (GET_CODE (set) != CLOBBER) 120290075Sobrien { 120390075Sobrien kill_value (x, vd); 120496263Sobrien if (REG_P (x)) 1205117395Skan set_value_regno (REGNO (x), GET_MODE (x), vd); 120690075Sobrien } 120790075Sobrien} 120890075Sobrien 120990075Sobrien/* Called through for_each_rtx. Kill any register used as the base of an 121090075Sobrien auto-increment expression, and install that register as the root of its 121190075Sobrien own value list. */ 121290075Sobrien 121390075Sobrienstatic int 1214132718Skankill_autoinc_value (rtx *px, void *data) 121590075Sobrien{ 121690075Sobrien rtx x = *px; 121790075Sobrien struct value_data *vd = data; 121890075Sobrien 1219169689Skan if (GET_RTX_CLASS (GET_CODE (x)) == RTX_AUTOINC) 122090075Sobrien { 122190075Sobrien x = XEXP (x, 0); 122290075Sobrien kill_value (x, vd); 122390075Sobrien set_value_regno (REGNO (x), Pmode, vd); 122490075Sobrien return -1; 122590075Sobrien } 122690075Sobrien 122790075Sobrien return 0; 122890075Sobrien} 122990075Sobrien 123090075Sobrien/* Assert that SRC has been copied to DEST. Adjust the data structures 123190075Sobrien to reflect that SRC contains an older copy of the shared value. */ 123290075Sobrien 123390075Sobrienstatic void 1234132718Skancopy_value (rtx dest, rtx src, struct value_data *vd) 123590075Sobrien{ 123690075Sobrien unsigned int dr = REGNO (dest); 123790075Sobrien unsigned int sr = REGNO (src); 123890075Sobrien unsigned int dn, sn; 123990075Sobrien unsigned int i; 124090075Sobrien 124190075Sobrien /* ??? At present, it's possible to see noop sets. It'd be nice if 124290075Sobrien this were cleaned up beforehand... */ 124390075Sobrien if (sr == dr) 124490075Sobrien return; 124590075Sobrien 124690075Sobrien /* Do not propagate copies to the stack pointer, as that can leave 1247117395Skan memory accesses with no scheduling dependency on the stack update. */ 124890075Sobrien if (dr == STACK_POINTER_REGNUM) 124990075Sobrien return; 125090075Sobrien 125190075Sobrien /* Likewise with the frame pointer, if we're using one. */ 125290075Sobrien if (frame_pointer_needed && dr == HARD_FRAME_POINTER_REGNUM) 125390075Sobrien return; 125490075Sobrien 1255169689Skan /* Do not propagate copies to fixed or global registers, patterns 1256169689Skan can be relying to see particular fixed register or users can 1257169689Skan expect the chosen global register in asm. */ 1258169689Skan if (fixed_regs[dr] || global_regs[dr]) 1259169689Skan return; 1260169689Skan 126190075Sobrien /* If SRC and DEST overlap, don't record anything. */ 1262169689Skan dn = hard_regno_nregs[dr][GET_MODE (dest)]; 1263169689Skan sn = hard_regno_nregs[sr][GET_MODE (dest)]; 126490075Sobrien if ((dr > sr && dr < sr + sn) 126590075Sobrien || (sr > dr && sr < dr + dn)) 126690075Sobrien return; 126790075Sobrien 126890075Sobrien /* If SRC had no assigned mode (i.e. we didn't know it was live) 126990075Sobrien assign it now and assume the value came from an input argument 127090075Sobrien or somesuch. */ 127190075Sobrien if (vd->e[sr].mode == VOIDmode) 127290075Sobrien set_value_regno (sr, vd->e[dr].mode, vd); 127390075Sobrien 1274117395Skan /* If we are narrowing the input to a smaller number of hard regs, 1275117395Skan and it is in big endian, we are really extracting a high part. 1276117395Skan Since we generally associate a low part of a value with the value itself, 1277117395Skan we must not do the same for the high part. 1278117395Skan Note we can still get low parts for the same mode combination through 1279117395Skan a two-step copy involving differently sized hard regs. 1280117395Skan Assume hard regs fr* are 32 bits bits each, while r* are 64 bits each: 1281117395Skan (set (reg:DI r0) (reg:DI fr0)) 1282117395Skan (set (reg:SI fr2) (reg:SI r0)) 1283117395Skan loads the low part of (reg:DI fr0) - i.e. fr1 - into fr2, while: 1284117395Skan (set (reg:SI fr2) (reg:SI fr0)) 1285117395Skan loads the high part of (reg:DI fr0) into fr2. 1286117395Skan 1287117395Skan We can't properly represent the latter case in our tables, so don't 1288117395Skan record anything then. */ 1289169689Skan else if (sn < (unsigned int) hard_regno_nregs[sr][vd->e[sr].mode] 1290117395Skan && (GET_MODE_SIZE (vd->e[sr].mode) > UNITS_PER_WORD 1291117395Skan ? WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN)) 1292117395Skan return; 1293117395Skan 129490075Sobrien /* If SRC had been assigned a mode narrower than the copy, we can't 129590075Sobrien link DEST into the chain, because not all of the pieces of the 129690075Sobrien copy came from oldest_regno. */ 1297169689Skan else if (sn > (unsigned int) hard_regno_nregs[sr][vd->e[sr].mode]) 129890075Sobrien return; 129990075Sobrien 130090075Sobrien /* Link DR at the end of the value chain used by SR. */ 130190075Sobrien 130290075Sobrien vd->e[dr].oldest_regno = vd->e[sr].oldest_regno; 130390075Sobrien 130490075Sobrien for (i = sr; vd->e[i].next_regno != INVALID_REGNUM; i = vd->e[i].next_regno) 130590075Sobrien continue; 130690075Sobrien vd->e[i].next_regno = dr; 130790075Sobrien 130890075Sobrien#ifdef ENABLE_CHECKING 130990075Sobrien validate_value_data (vd); 131090075Sobrien#endif 131190075Sobrien} 131290075Sobrien 131390075Sobrien/* Return true if a mode change from ORIG to NEW is allowed for REGNO. */ 131490075Sobrien 131590075Sobrienstatic bool 1316132718Skanmode_change_ok (enum machine_mode orig_mode, enum machine_mode new_mode, 1317132718Skan unsigned int regno ATTRIBUTE_UNUSED) 131890075Sobrien{ 131990075Sobrien if (GET_MODE_SIZE (orig_mode) < GET_MODE_SIZE (new_mode)) 132090075Sobrien return false; 132190075Sobrien 1322117395Skan#ifdef CANNOT_CHANGE_MODE_CLASS 1323117395Skan return !REG_CANNOT_CHANGE_MODE_P (regno, orig_mode, new_mode); 132490075Sobrien#endif 132590075Sobrien 132690075Sobrien return true; 132790075Sobrien} 132890075Sobrien 1329117395Skan/* Register REGNO was originally set in ORIG_MODE. It - or a copy of it - 1330117395Skan was copied in COPY_MODE to COPY_REGNO, and then COPY_REGNO was accessed 1331117395Skan in NEW_MODE. 1332117395Skan Return a NEW_MODE rtx for REGNO if that's OK, otherwise return NULL_RTX. */ 1333117395Skan 1334117395Skanstatic rtx 1335132718Skanmaybe_mode_change (enum machine_mode orig_mode, enum machine_mode copy_mode, 1336132718Skan enum machine_mode new_mode, unsigned int regno, 1337132718Skan unsigned int copy_regno ATTRIBUTE_UNUSED) 1338117395Skan{ 1339117395Skan if (orig_mode == new_mode) 1340117395Skan return gen_rtx_raw_REG (new_mode, regno); 1341117395Skan else if (mode_change_ok (orig_mode, new_mode, regno)) 1342117395Skan { 1343169689Skan int copy_nregs = hard_regno_nregs[copy_regno][copy_mode]; 1344169689Skan int use_nregs = hard_regno_nregs[copy_regno][new_mode]; 1345117395Skan int copy_offset 1346117395Skan = GET_MODE_SIZE (copy_mode) / copy_nregs * (copy_nregs - use_nregs); 1347117395Skan int offset 1348117395Skan = GET_MODE_SIZE (orig_mode) - GET_MODE_SIZE (new_mode) - copy_offset; 1349117395Skan int byteoffset = offset % UNITS_PER_WORD; 1350117395Skan int wordoffset = offset - byteoffset; 1351117395Skan 1352117395Skan offset = ((WORDS_BIG_ENDIAN ? wordoffset : 0) 1353117395Skan + (BYTES_BIG_ENDIAN ? byteoffset : 0)); 1354117395Skan return gen_rtx_raw_REG (new_mode, 1355117395Skan regno + subreg_regno_offset (regno, orig_mode, 1356117395Skan offset, 1357117395Skan new_mode)); 1358117395Skan } 1359117395Skan return NULL_RTX; 1360117395Skan} 1361117395Skan 136290075Sobrien/* Find the oldest copy of the value contained in REGNO that is in 1363169689Skan register class CL and has mode MODE. If found, return an rtx 136490075Sobrien of that oldest register, otherwise return NULL. */ 136590075Sobrien 136690075Sobrienstatic rtx 1367169689Skanfind_oldest_value_reg (enum reg_class cl, rtx reg, struct value_data *vd) 136890075Sobrien{ 136990075Sobrien unsigned int regno = REGNO (reg); 137090075Sobrien enum machine_mode mode = GET_MODE (reg); 137190075Sobrien unsigned int i; 137290075Sobrien 137390075Sobrien /* If we are accessing REG in some mode other that what we set it in, 137490075Sobrien make sure that the replacement is valid. In particular, consider 137590075Sobrien (set (reg:DI r11) (...)) 137690075Sobrien (set (reg:SI r9) (reg:SI r11)) 137790075Sobrien (set (reg:SI r10) (...)) 137890075Sobrien (set (...) (reg:DI r9)) 137990075Sobrien Replacing r9 with r11 is invalid. */ 138090075Sobrien if (mode != vd->e[regno].mode) 138190075Sobrien { 1382169689Skan if (hard_regno_nregs[regno][mode] 1383169689Skan > hard_regno_nregs[regno][vd->e[regno].mode]) 138490075Sobrien return NULL_RTX; 138590075Sobrien } 138690075Sobrien 138790075Sobrien for (i = vd->e[regno].oldest_regno; i != regno; i = vd->e[i].next_regno) 1388117395Skan { 1389117395Skan enum machine_mode oldmode = vd->e[i].mode; 1390117395Skan rtx new; 1391132718Skan unsigned int last; 1392117395Skan 1393169689Skan for (last = i; last < i + hard_regno_nregs[i][mode]; last++) 1394169689Skan if (!TEST_HARD_REG_BIT (reg_class_contents[cl], last)) 1395132718Skan return NULL_RTX; 1396132718Skan 1397132718Skan new = maybe_mode_change (oldmode, vd->e[regno].mode, mode, i, regno); 1398132718Skan if (new) 1399132718Skan { 1400132718Skan ORIGINAL_REGNO (new) = ORIGINAL_REGNO (reg); 1401132718Skan REG_ATTRS (new) = REG_ATTRS (reg); 1402132718Skan return new; 1403132718Skan } 1404117395Skan } 140590075Sobrien 140690075Sobrien return NULL_RTX; 140790075Sobrien} 140890075Sobrien 140990075Sobrien/* If possible, replace the register at *LOC with the oldest register 1410169689Skan in register class CL. Return true if successfully replaced. */ 141190075Sobrien 141290075Sobrienstatic bool 1413169689Skanreplace_oldest_value_reg (rtx *loc, enum reg_class cl, rtx insn, 1414132718Skan struct value_data *vd) 141590075Sobrien{ 1416169689Skan rtx new = find_oldest_value_reg (cl, *loc, vd); 141790075Sobrien if (new) 141890075Sobrien { 1419169689Skan if (dump_file) 1420169689Skan fprintf (dump_file, "insn %u: replaced reg %u with %u\n", 142190075Sobrien INSN_UID (insn), REGNO (*loc), REGNO (new)); 142290075Sobrien 1423169689Skan validate_change (insn, loc, new, 1); 142490075Sobrien return true; 142590075Sobrien } 142690075Sobrien return false; 142790075Sobrien} 142890075Sobrien 142990075Sobrien/* Similar to replace_oldest_value_reg, but *LOC contains an address. 1430169689Skan Adapted from find_reloads_address_1. CL is INDEX_REG_CLASS or 143190075Sobrien BASE_REG_CLASS depending on how the register is being considered. */ 143290075Sobrien 143390075Sobrienstatic bool 1434169689Skanreplace_oldest_value_addr (rtx *loc, enum reg_class cl, 1435132718Skan enum machine_mode mode, rtx insn, 1436132718Skan struct value_data *vd) 143790075Sobrien{ 143890075Sobrien rtx x = *loc; 143990075Sobrien RTX_CODE code = GET_CODE (x); 144090075Sobrien const char *fmt; 144190075Sobrien int i, j; 144290075Sobrien bool changed = false; 144390075Sobrien 144490075Sobrien switch (code) 144590075Sobrien { 144690075Sobrien case PLUS: 144790075Sobrien { 144890075Sobrien rtx orig_op0 = XEXP (x, 0); 144990075Sobrien rtx orig_op1 = XEXP (x, 1); 145090075Sobrien RTX_CODE code0 = GET_CODE (orig_op0); 145190075Sobrien RTX_CODE code1 = GET_CODE (orig_op1); 145290075Sobrien rtx op0 = orig_op0; 145390075Sobrien rtx op1 = orig_op1; 145490075Sobrien rtx *locI = NULL; 145590075Sobrien rtx *locB = NULL; 1456169689Skan enum rtx_code index_code = SCRATCH; 145790075Sobrien 145890075Sobrien if (GET_CODE (op0) == SUBREG) 145990075Sobrien { 146090075Sobrien op0 = SUBREG_REG (op0); 146190075Sobrien code0 = GET_CODE (op0); 146290075Sobrien } 146390075Sobrien 146490075Sobrien if (GET_CODE (op1) == SUBREG) 146590075Sobrien { 146690075Sobrien op1 = SUBREG_REG (op1); 146790075Sobrien code1 = GET_CODE (op1); 146890075Sobrien } 146990075Sobrien 147090075Sobrien if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE 147190075Sobrien || code0 == ZERO_EXTEND || code1 == MEM) 147290075Sobrien { 147390075Sobrien locI = &XEXP (x, 0); 147490075Sobrien locB = &XEXP (x, 1); 1475169689Skan index_code = GET_CODE (*locI); 147690075Sobrien } 147790075Sobrien else if (code1 == MULT || code1 == SIGN_EXTEND || code1 == TRUNCATE 147890075Sobrien || code1 == ZERO_EXTEND || code0 == MEM) 147990075Sobrien { 148090075Sobrien locI = &XEXP (x, 1); 148190075Sobrien locB = &XEXP (x, 0); 1482169689Skan index_code = GET_CODE (*locI); 148390075Sobrien } 148490075Sobrien else if (code0 == CONST_INT || code0 == CONST 148590075Sobrien || code0 == SYMBOL_REF || code0 == LABEL_REF) 1486169689Skan { 1487169689Skan locB = &XEXP (x, 1); 1488169689Skan index_code = GET_CODE (XEXP (x, 0)); 1489169689Skan } 149090075Sobrien else if (code1 == CONST_INT || code1 == CONST 149190075Sobrien || code1 == SYMBOL_REF || code1 == LABEL_REF) 1492169689Skan { 1493169689Skan locB = &XEXP (x, 0); 1494169689Skan index_code = GET_CODE (XEXP (x, 1)); 1495169689Skan } 149690075Sobrien else if (code0 == REG && code1 == REG) 149790075Sobrien { 149890075Sobrien int index_op; 1499169689Skan unsigned regno0 = REGNO (op0), regno1 = REGNO (op1); 150090075Sobrien 1501169689Skan if (REGNO_OK_FOR_INDEX_P (regno0) 1502169689Skan && regno_ok_for_base_p (regno1, mode, PLUS, REG)) 150390075Sobrien index_op = 0; 1504169689Skan else if (REGNO_OK_FOR_INDEX_P (regno1) 1505169689Skan && regno_ok_for_base_p (regno0, mode, PLUS, REG)) 150690075Sobrien index_op = 1; 1507169689Skan else if (regno_ok_for_base_p (regno1, mode, PLUS, REG)) 150890075Sobrien index_op = 0; 1509169689Skan else if (regno_ok_for_base_p (regno0, mode, PLUS, REG)) 151090075Sobrien index_op = 1; 1511169689Skan else if (REGNO_OK_FOR_INDEX_P (regno1)) 151290075Sobrien index_op = 1; 151390075Sobrien else 151490075Sobrien index_op = 0; 151590075Sobrien 151690075Sobrien locI = &XEXP (x, index_op); 151790075Sobrien locB = &XEXP (x, !index_op); 1518169689Skan index_code = GET_CODE (*locI); 151990075Sobrien } 152090075Sobrien else if (code0 == REG) 152190075Sobrien { 152290075Sobrien locI = &XEXP (x, 0); 152390075Sobrien locB = &XEXP (x, 1); 1524169689Skan index_code = GET_CODE (*locI); 152590075Sobrien } 152690075Sobrien else if (code1 == REG) 152790075Sobrien { 152890075Sobrien locI = &XEXP (x, 1); 152990075Sobrien locB = &XEXP (x, 0); 1530169689Skan index_code = GET_CODE (*locI); 153190075Sobrien } 153290075Sobrien 153390075Sobrien if (locI) 153490075Sobrien changed |= replace_oldest_value_addr (locI, INDEX_REG_CLASS, mode, 1535117395Skan insn, vd); 153690075Sobrien if (locB) 153790075Sobrien changed |= replace_oldest_value_addr (locB, 1538169689Skan base_reg_class (mode, PLUS, 1539169689Skan index_code), 154090075Sobrien mode, insn, vd); 154190075Sobrien return changed; 154290075Sobrien } 154390075Sobrien 154490075Sobrien case POST_INC: 154590075Sobrien case POST_DEC: 154690075Sobrien case POST_MODIFY: 154790075Sobrien case PRE_INC: 154890075Sobrien case PRE_DEC: 154990075Sobrien case PRE_MODIFY: 155090075Sobrien return false; 155190075Sobrien 155290075Sobrien case MEM: 155390075Sobrien return replace_oldest_value_mem (x, insn, vd); 155490075Sobrien 155590075Sobrien case REG: 1556169689Skan return replace_oldest_value_reg (loc, cl, insn, vd); 155790075Sobrien 155890075Sobrien default: 155990075Sobrien break; 156090075Sobrien } 156190075Sobrien 156290075Sobrien fmt = GET_RTX_FORMAT (code); 156390075Sobrien for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) 156490075Sobrien { 156590075Sobrien if (fmt[i] == 'e') 1566169689Skan changed |= replace_oldest_value_addr (&XEXP (x, i), cl, mode, 156790075Sobrien insn, vd); 156890075Sobrien else if (fmt[i] == 'E') 156990075Sobrien for (j = XVECLEN (x, i) - 1; j >= 0; j--) 1570169689Skan changed |= replace_oldest_value_addr (&XVECEXP (x, i, j), cl, 1571117395Skan mode, insn, vd); 157290075Sobrien } 157390075Sobrien 157490075Sobrien return changed; 157590075Sobrien} 157690075Sobrien 157790075Sobrien/* Similar to replace_oldest_value_reg, but X contains a memory. */ 157890075Sobrien 157990075Sobrienstatic bool 1580132718Skanreplace_oldest_value_mem (rtx x, rtx insn, struct value_data *vd) 158190075Sobrien{ 158290075Sobrien return replace_oldest_value_addr (&XEXP (x, 0), 1583169689Skan base_reg_class (GET_MODE (x), MEM, 1584169689Skan SCRATCH), 158590075Sobrien GET_MODE (x), insn, vd); 158690075Sobrien} 158790075Sobrien 158890075Sobrien/* Perform the forward copy propagation on basic block BB. */ 158990075Sobrien 159090075Sobrienstatic bool 1591132718Skancopyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd) 159290075Sobrien{ 159390075Sobrien bool changed = false; 159490075Sobrien rtx insn; 159590075Sobrien 1596132718Skan for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn)) 159790075Sobrien { 159890075Sobrien int n_ops, i, alt, predicated; 1599169689Skan bool is_asm, any_replacements; 160090075Sobrien rtx set; 1601169689Skan bool replaced[MAX_RECOG_OPERANDS]; 160290075Sobrien 160390075Sobrien if (! INSN_P (insn)) 160490075Sobrien { 1605132718Skan if (insn == BB_END (bb)) 160690075Sobrien break; 160790075Sobrien else 160890075Sobrien continue; 160990075Sobrien } 161090075Sobrien 161190075Sobrien set = single_set (insn); 161290075Sobrien extract_insn (insn); 1613117395Skan if (! constrain_operands (1)) 1614117395Skan fatal_insn_not_found (insn); 161590075Sobrien preprocess_constraints (); 161690075Sobrien alt = which_alternative; 161790075Sobrien n_ops = recog_data.n_operands; 161890075Sobrien is_asm = asm_noperands (PATTERN (insn)) >= 0; 161990075Sobrien 162090075Sobrien /* Simplify the code below by rewriting things to reflect 162190075Sobrien matching constraints. Also promote OP_OUT to OP_INOUT 162290075Sobrien in predicated instructions. */ 162390075Sobrien 162490075Sobrien predicated = GET_CODE (PATTERN (insn)) == COND_EXEC; 162590075Sobrien for (i = 0; i < n_ops; ++i) 162690075Sobrien { 162790075Sobrien int matches = recog_op_alt[i][alt].matches; 162890075Sobrien if (matches >= 0) 1629169689Skan recog_op_alt[i][alt].cl = recog_op_alt[matches][alt].cl; 163090075Sobrien if (matches >= 0 || recog_op_alt[i][alt].matched >= 0 163190075Sobrien || (predicated && recog_data.operand_type[i] == OP_OUT)) 163290075Sobrien recog_data.operand_type[i] = OP_INOUT; 163390075Sobrien } 163490075Sobrien 163590075Sobrien /* For each earlyclobber operand, zap the value data. */ 163690075Sobrien for (i = 0; i < n_ops; i++) 163790075Sobrien if (recog_op_alt[i][alt].earlyclobber) 163890075Sobrien kill_value (recog_data.operand[i], vd); 163990075Sobrien 164090075Sobrien /* Within asms, a clobber cannot overlap inputs or outputs. 164190075Sobrien I wouldn't think this were true for regular insns, but 164290075Sobrien scan_rtx treats them like that... */ 164390075Sobrien note_stores (PATTERN (insn), kill_clobbered_value, vd); 164490075Sobrien 164590075Sobrien /* Kill all auto-incremented values. */ 164690075Sobrien /* ??? REG_INC is useless, since stack pushes aren't done that way. */ 164790075Sobrien for_each_rtx (&PATTERN (insn), kill_autoinc_value, vd); 164890075Sobrien 164990075Sobrien /* Kill all early-clobbered operands. */ 165090075Sobrien for (i = 0; i < n_ops; i++) 165190075Sobrien if (recog_op_alt[i][alt].earlyclobber) 165290075Sobrien kill_value (recog_data.operand[i], vd); 165390075Sobrien 165490075Sobrien /* Special-case plain move instructions, since we may well 165590075Sobrien be able to do the move from a different register class. */ 165690075Sobrien if (set && REG_P (SET_SRC (set))) 165790075Sobrien { 165890075Sobrien rtx src = SET_SRC (set); 165990075Sobrien unsigned int regno = REGNO (src); 166090075Sobrien enum machine_mode mode = GET_MODE (src); 166190075Sobrien unsigned int i; 166290075Sobrien rtx new; 166390075Sobrien 166490075Sobrien /* If we are accessing SRC in some mode other that what we 166590075Sobrien set it in, make sure that the replacement is valid. */ 166690075Sobrien if (mode != vd->e[regno].mode) 166790075Sobrien { 1668169689Skan if (hard_regno_nregs[regno][mode] 1669169689Skan > hard_regno_nregs[regno][vd->e[regno].mode]) 167090075Sobrien goto no_move_special_case; 167190075Sobrien } 167290075Sobrien 167390075Sobrien /* If the destination is also a register, try to find a source 167490075Sobrien register in the same class. */ 167590075Sobrien if (REG_P (SET_DEST (set))) 167690075Sobrien { 167790075Sobrien new = find_oldest_value_reg (REGNO_REG_CLASS (regno), src, vd); 167890075Sobrien if (new && validate_change (insn, &SET_SRC (set), new, 0)) 167990075Sobrien { 1680169689Skan if (dump_file) 1681169689Skan fprintf (dump_file, 168290075Sobrien "insn %u: replaced reg %u with %u\n", 168390075Sobrien INSN_UID (insn), regno, REGNO (new)); 1684117395Skan changed = true; 168590075Sobrien goto did_replacement; 168690075Sobrien } 168790075Sobrien } 168890075Sobrien 168990075Sobrien /* Otherwise, try all valid registers and see if its valid. */ 169090075Sobrien for (i = vd->e[regno].oldest_regno; i != regno; 169190075Sobrien i = vd->e[i].next_regno) 1692117395Skan { 1693117395Skan new = maybe_mode_change (vd->e[i].mode, vd->e[regno].mode, 1694117395Skan mode, i, regno); 1695117395Skan if (new != NULL_RTX) 1696117395Skan { 1697117395Skan if (validate_change (insn, &SET_SRC (set), new, 0)) 1698117395Skan { 1699117395Skan ORIGINAL_REGNO (new) = ORIGINAL_REGNO (src); 1700132718Skan REG_ATTRS (new) = REG_ATTRS (src); 1701169689Skan if (dump_file) 1702169689Skan fprintf (dump_file, 1703117395Skan "insn %u: replaced reg %u with %u\n", 1704117395Skan INSN_UID (insn), regno, REGNO (new)); 1705117395Skan changed = true; 1706117395Skan goto did_replacement; 1707117395Skan } 1708117395Skan } 1709117395Skan } 171090075Sobrien } 171190075Sobrien no_move_special_case: 171290075Sobrien 1713169689Skan any_replacements = false; 1714169689Skan 171590075Sobrien /* For each input operand, replace a hard register with the 171690075Sobrien eldest live copy that's in an appropriate register class. */ 171790075Sobrien for (i = 0; i < n_ops; i++) 171890075Sobrien { 1719169689Skan replaced[i] = false; 172090075Sobrien 172190075Sobrien /* Don't scan match_operand here, since we've no reg class 172290075Sobrien information to pass down. Any operands that we could 172390075Sobrien substitute in will be represented elsewhere. */ 172490075Sobrien if (recog_data.constraints[i][0] == '\0') 172590075Sobrien continue; 172690075Sobrien 172790075Sobrien /* Don't replace in asms intentionally referencing hard regs. */ 1728169689Skan if (is_asm && REG_P (recog_data.operand[i]) 172990075Sobrien && (REGNO (recog_data.operand[i]) 173090075Sobrien == ORIGINAL_REGNO (recog_data.operand[i]))) 173190075Sobrien continue; 173290075Sobrien 173390075Sobrien if (recog_data.operand_type[i] == OP_IN) 173490075Sobrien { 173590075Sobrien if (recog_op_alt[i][alt].is_address) 1736169689Skan replaced[i] 173790075Sobrien = replace_oldest_value_addr (recog_data.operand_loc[i], 1738169689Skan recog_op_alt[i][alt].cl, 173990075Sobrien VOIDmode, insn, vd); 174090075Sobrien else if (REG_P (recog_data.operand[i])) 1741169689Skan replaced[i] 174290075Sobrien = replace_oldest_value_reg (recog_data.operand_loc[i], 1743169689Skan recog_op_alt[i][alt].cl, 174490075Sobrien insn, vd); 1745169689Skan else if (MEM_P (recog_data.operand[i])) 1746169689Skan replaced[i] = replace_oldest_value_mem (recog_data.operand[i], 1747169689Skan insn, vd); 174890075Sobrien } 1749169689Skan else if (MEM_P (recog_data.operand[i])) 1750169689Skan replaced[i] = replace_oldest_value_mem (recog_data.operand[i], 1751169689Skan insn, vd); 175290075Sobrien 175390075Sobrien /* If we performed any replacement, update match_dups. */ 1754169689Skan if (replaced[i]) 175590075Sobrien { 175690075Sobrien int j; 175790075Sobrien rtx new; 175890075Sobrien 175990075Sobrien new = *recog_data.operand_loc[i]; 176090075Sobrien recog_data.operand[i] = new; 176190075Sobrien for (j = 0; j < recog_data.n_dups; j++) 176290075Sobrien if (recog_data.dup_num[j] == i) 1763169689Skan validate_change (insn, recog_data.dup_loc[j], new, 1); 1764169689Skan 1765169689Skan any_replacements = true; 176690075Sobrien } 176790075Sobrien } 176890075Sobrien 1769169689Skan if (any_replacements) 1770169689Skan { 1771169689Skan if (! apply_change_group ()) 1772169689Skan { 1773169689Skan for (i = 0; i < n_ops; i++) 1774169689Skan if (replaced[i]) 1775169689Skan { 1776169689Skan rtx old = *recog_data.operand_loc[i]; 1777169689Skan recog_data.operand[i] = old; 1778169689Skan } 1779169689Skan 1780169689Skan if (dump_file) 1781169689Skan fprintf (dump_file, 1782169689Skan "insn %u: reg replacements not verified\n", 1783169689Skan INSN_UID (insn)); 1784169689Skan } 1785169689Skan else 1786169689Skan changed = true; 1787169689Skan } 1788169689Skan 178990075Sobrien did_replacement: 179090075Sobrien /* Clobber call-clobbered registers. */ 1791169689Skan if (CALL_P (insn)) 179290075Sobrien for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 179390075Sobrien if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i)) 1794169689Skan kill_value_regno (i, 1, vd); 179590075Sobrien 179690075Sobrien /* Notice stores. */ 179790075Sobrien note_stores (PATTERN (insn), kill_set_value, vd); 179890075Sobrien 179990075Sobrien /* Notice copies. */ 180090075Sobrien if (set && REG_P (SET_DEST (set)) && REG_P (SET_SRC (set))) 180190075Sobrien copy_value (SET_DEST (set), SET_SRC (set), vd); 180290075Sobrien 1803132718Skan if (insn == BB_END (bb)) 180490075Sobrien break; 180590075Sobrien } 180690075Sobrien 180790075Sobrien return changed; 180890075Sobrien} 180990075Sobrien 181090075Sobrien/* Main entry point for the forward copy propagation optimization. */ 181190075Sobrien 1812169689Skanstatic void 1813132718Skancopyprop_hardreg_forward (void) 181490075Sobrien{ 181590075Sobrien struct value_data *all_vd; 181690075Sobrien bool need_refresh; 1817169689Skan basic_block bb; 1818169689Skan sbitmap visited; 181990075Sobrien 182090075Sobrien need_refresh = false; 182190075Sobrien 1822169689Skan all_vd = XNEWVEC (struct value_data, last_basic_block); 182390075Sobrien 1824169689Skan visited = sbitmap_alloc (last_basic_block); 1825169689Skan sbitmap_zero (visited); 1826169689Skan 1827117395Skan FOR_EACH_BB (bb) 182890075Sobrien { 1829169689Skan SET_BIT (visited, bb->index); 1830169689Skan 183190075Sobrien /* If a block has a single predecessor, that we've already 183290075Sobrien processed, begin with the value data that was live at 183390075Sobrien the end of the predecessor block. */ 1834132718Skan /* ??? Ought to use more intelligent queuing of blocks. */ 1835169689Skan if (single_pred_p (bb) 1836169689Skan && TEST_BIT (visited, single_pred (bb)->index) 1837169689Skan && ! (single_pred_edge (bb)->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))) 1838169689Skan all_vd[bb->index] = all_vd[single_pred (bb)->index]; 183990075Sobrien else 1840117395Skan init_value_data (all_vd + bb->index); 184190075Sobrien 1842117395Skan if (copyprop_hardreg_forward_1 (bb, all_vd + bb->index)) 184390075Sobrien need_refresh = true; 184490075Sobrien } 184590075Sobrien 1846169689Skan sbitmap_free (visited); 1847169689Skan 184890075Sobrien if (need_refresh) 184990075Sobrien { 1850169689Skan if (dump_file) 1851169689Skan fputs ("\n\n", dump_file); 185290075Sobrien 185390075Sobrien /* ??? Irritatingly, delete_noop_moves does not take a set of blocks 185490075Sobrien to scan, so we have to do a life update with no initial set of 185590075Sobrien blocks Just In Case. */ 1856169689Skan delete_noop_moves (); 185790075Sobrien update_life_info (NULL, UPDATE_LIFE_GLOBAL_RM_NOTES, 185890075Sobrien PROP_DEATH_NOTES 185990075Sobrien | PROP_SCAN_DEAD_CODE 186090075Sobrien | PROP_KILL_DEAD_CODE); 186190075Sobrien } 186290075Sobrien 186390075Sobrien free (all_vd); 186490075Sobrien} 186590075Sobrien 186690075Sobrien/* Dump the value chain data to stderr. */ 186790075Sobrien 186890075Sobrienvoid 1869132718Skandebug_value_data (struct value_data *vd) 187090075Sobrien{ 187190075Sobrien HARD_REG_SET set; 187290075Sobrien unsigned int i, j; 187390075Sobrien 187490075Sobrien CLEAR_HARD_REG_SET (set); 187590075Sobrien 187690075Sobrien for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i) 187790075Sobrien if (vd->e[i].oldest_regno == i) 187890075Sobrien { 187990075Sobrien if (vd->e[i].mode == VOIDmode) 188090075Sobrien { 188190075Sobrien if (vd->e[i].next_regno != INVALID_REGNUM) 188290075Sobrien fprintf (stderr, "[%u] Bad next_regno for empty chain (%u)\n", 188390075Sobrien i, vd->e[i].next_regno); 188490075Sobrien continue; 188590075Sobrien } 188690075Sobrien 188790075Sobrien SET_HARD_REG_BIT (set, i); 188890075Sobrien fprintf (stderr, "[%u %s] ", i, GET_MODE_NAME (vd->e[i].mode)); 188990075Sobrien 189090075Sobrien for (j = vd->e[i].next_regno; 189190075Sobrien j != INVALID_REGNUM; 189290075Sobrien j = vd->e[j].next_regno) 189390075Sobrien { 189490075Sobrien if (TEST_HARD_REG_BIT (set, j)) 189590075Sobrien { 189690075Sobrien fprintf (stderr, "[%u] Loop in regno chain\n", j); 189790075Sobrien return; 189890075Sobrien } 189990075Sobrien 190090075Sobrien if (vd->e[j].oldest_regno != i) 190190075Sobrien { 190290075Sobrien fprintf (stderr, "[%u] Bad oldest_regno (%u)\n", 190390075Sobrien j, vd->e[j].oldest_regno); 190490075Sobrien return; 190590075Sobrien } 190690075Sobrien SET_HARD_REG_BIT (set, j); 190790075Sobrien fprintf (stderr, "[%u %s] ", j, GET_MODE_NAME (vd->e[j].mode)); 190890075Sobrien } 190990075Sobrien fputc ('\n', stderr); 191090075Sobrien } 191190075Sobrien 191290075Sobrien for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i) 191390075Sobrien if (! TEST_HARD_REG_BIT (set, i) 191490075Sobrien && (vd->e[i].mode != VOIDmode 191590075Sobrien || vd->e[i].oldest_regno != i 191690075Sobrien || vd->e[i].next_regno != INVALID_REGNUM)) 191790075Sobrien fprintf (stderr, "[%u] Non-empty reg in chain (%s %u %i)\n", 191890075Sobrien i, GET_MODE_NAME (vd->e[i].mode), vd->e[i].oldest_regno, 191990075Sobrien vd->e[i].next_regno); 192090075Sobrien} 192190075Sobrien 192290075Sobrien#ifdef ENABLE_CHECKING 192390075Sobrienstatic void 1924132718Skanvalidate_value_data (struct value_data *vd) 192590075Sobrien{ 192690075Sobrien HARD_REG_SET set; 192790075Sobrien unsigned int i, j; 192890075Sobrien 192990075Sobrien CLEAR_HARD_REG_SET (set); 193090075Sobrien 193190075Sobrien for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i) 193290075Sobrien if (vd->e[i].oldest_regno == i) 193390075Sobrien { 193490075Sobrien if (vd->e[i].mode == VOIDmode) 193590075Sobrien { 193690075Sobrien if (vd->e[i].next_regno != INVALID_REGNUM) 193790075Sobrien internal_error ("validate_value_data: [%u] Bad next_regno for empty chain (%u)", 193890075Sobrien i, vd->e[i].next_regno); 193990075Sobrien continue; 194090075Sobrien } 194190075Sobrien 194290075Sobrien SET_HARD_REG_BIT (set, i); 194390075Sobrien 194490075Sobrien for (j = vd->e[i].next_regno; 194590075Sobrien j != INVALID_REGNUM; 194690075Sobrien j = vd->e[j].next_regno) 194790075Sobrien { 194890075Sobrien if (TEST_HARD_REG_BIT (set, j)) 194990075Sobrien internal_error ("validate_value_data: Loop in regno chain (%u)", 195090075Sobrien j); 195190075Sobrien if (vd->e[j].oldest_regno != i) 195290075Sobrien internal_error ("validate_value_data: [%u] Bad oldest_regno (%u)", 195390075Sobrien j, vd->e[j].oldest_regno); 195490075Sobrien 195590075Sobrien SET_HARD_REG_BIT (set, j); 195690075Sobrien } 195790075Sobrien } 195890075Sobrien 195990075Sobrien for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i) 196090075Sobrien if (! TEST_HARD_REG_BIT (set, i) 196190075Sobrien && (vd->e[i].mode != VOIDmode 196290075Sobrien || vd->e[i].oldest_regno != i 196390075Sobrien || vd->e[i].next_regno != INVALID_REGNUM)) 196490075Sobrien internal_error ("validate_value_data: [%u] Non-empty reg in chain (%s %u %i)", 196590075Sobrien i, GET_MODE_NAME (vd->e[i].mode), vd->e[i].oldest_regno, 196690075Sobrien vd->e[i].next_regno); 196790075Sobrien} 196890075Sobrien#endif 1969169689Skan 1970169689Skanstatic bool 1971169689Skangate_handle_regrename (void) 1972169689Skan{ 1973169689Skan return (optimize > 0 && (flag_rename_registers || flag_cprop_registers)); 1974169689Skan} 1975169689Skan 1976169689Skan 1977169689Skan/* Run the regrename and cprop passes. */ 1978169689Skanstatic unsigned int 1979169689Skanrest_of_handle_regrename (void) 1980169689Skan{ 1981169689Skan if (flag_rename_registers) 1982169689Skan regrename_optimize (); 1983169689Skan if (flag_cprop_registers) 1984169689Skan copyprop_hardreg_forward (); 1985169689Skan return 0; 1986169689Skan} 1987169689Skan 1988169689Skanstruct tree_opt_pass pass_regrename = 1989169689Skan{ 1990169689Skan "rnreg", /* name */ 1991169689Skan gate_handle_regrename, /* gate */ 1992169689Skan rest_of_handle_regrename, /* execute */ 1993169689Skan NULL, /* sub */ 1994169689Skan NULL, /* next */ 1995169689Skan 0, /* static_pass_number */ 1996169689Skan TV_RENAME_REGISTERS, /* tv_id */ 1997169689Skan 0, /* properties_required */ 1998169689Skan 0, /* properties_provided */ 1999169689Skan 0, /* properties_destroyed */ 2000169689Skan 0, /* todo_flags_start */ 2001169689Skan TODO_dump_func, /* todo_flags_finish */ 2002169689Skan 'n' /* letter */ 2003169689Skan}; 2004169689Skan 2005