mode-switching.c revision 169689
178556Sobrien/* CPU mode switching 278556Sobrien Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 378556Sobrien Free Software Foundation, Inc. 478556Sobrien 578556SobrienThis file is part of GCC. 678556Sobrien 7167974SdelphijGCC is free software; you can redistribute it and/or modify it under 8167974Sdelphijthe terms of the GNU General Public License as published by the Free 9167974SdelphijSoftware Foundation; either version 2, or (at your option) any later 1078556Sobrienversion. 11215041Sobrien 12215041SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY 1378556SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or 14167974SdelphijFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15167974Sdelphijfor more details. 1678556Sobrien 17167974SdelphijYou should have received a copy of the GNU General Public License 18167974Sdelphijalong with GCC; see the file COPYING. If not, write to the Free 19167974SdelphijSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 2078556Sobrien02110-1301, USA. */ 2178556Sobrien 22167974Sdelphij#include "config.h" 23167974Sdelphij#include "system.h" 24167974Sdelphij#include "coretypes.h" 25167974Sdelphij#include "tm.h" 26167974Sdelphij#include "rtl.h" 27167974Sdelphij#include "regs.h" 2878556Sobrien#include "hard-reg-set.h" 2978556Sobrien#include "flags.h" 3078556Sobrien#include "real.h" 3178556Sobrien#include "insn-config.h" 3278556Sobrien#include "recog.h" 3378556Sobrien#include "basic-block.h" 3478556Sobrien#include "output.h" 3578556Sobrien#include "tm_p.h" 3678556Sobrien#include "function.h" 3778556Sobrien#include "tree-pass.h" 3878556Sobrien#include "timevar.h" 3978556Sobrien 4078556Sobrien/* We want target macros for the mode switching code to be able to refer 4178556Sobrien to instruction attribute values. */ 4278556Sobrien#include "insn-attr.h" 4378556Sobrien 4478556Sobrien#ifdef OPTIMIZE_MODE_SWITCHING 4578556Sobrien 4678556Sobrien/* The algorithm for setting the modes consists of scanning the insn list 4778556Sobrien and finding all the insns which require a specific mode. Each insn gets 4878556Sobrien a unique struct seginfo element. These structures are inserted into a list 4978556Sobrien for each basic block. For each entity, there is an array of bb_info over 5078556Sobrien the flow graph basic blocks (local var 'bb_info'), and contains a list 5178556Sobrien of all insns within that basic block, in the order they are encountered. 5278556Sobrien 5378556Sobrien For each entity, any basic block WITHOUT any insns requiring a specific 5478556Sobrien mode are given a single entry, without a mode. (Each basic block 5578556Sobrien in the flow graph must have at least one entry in the segment table.) 5678556Sobrien 5778556Sobrien The LCM algorithm is then run over the flow graph to determine where to 5878556Sobrien place the sets to the highest-priority value in respect of first the first 5978556Sobrien insn in any one block. Any adjustments required to the transparency 6078556Sobrien vectors are made, then the next iteration starts for the next-lower 6178556Sobrien priority mode, till for each entity all modes are exhausted. 6278556Sobrien 6378556Sobrien More details are located in the code for optimize_mode_switching(). */ 6478556Sobrien 6578556Sobrien/* This structure contains the information for each insn which requires 6678556Sobrien either single or double mode to be set. 6778556Sobrien MODE is the mode this insn must be executed in. 6878556Sobrien INSN_PTR is the insn to be executed (may be the note that marks the 6978556Sobrien beginning of a basic block). 7078556Sobrien BBNUM is the flow graph basic block this insn occurs in. 7178556Sobrien NEXT is the next insn in the same basic block. */ 7278556Sobrienstruct seginfo 7378556Sobrien{ 7478556Sobrien int mode; 7578556Sobrien rtx insn_ptr; 7678556Sobrien int bbnum; 7778556Sobrien struct seginfo *next; 7878556Sobrien HARD_REG_SET regs_live; 7978556Sobrien}; 8078556Sobrien 8178556Sobrienstruct bb_info 8278556Sobrien{ 8378556Sobrien struct seginfo *seginfo; 8478556Sobrien int computing; 8578556Sobrien}; 8678556Sobrien 8778556Sobrien/* These bitmaps are used for the LCM algorithm. */ 8878556Sobrien 8978556Sobrienstatic sbitmap *antic; 9078556Sobrienstatic sbitmap *transp; 9178556Sobrienstatic sbitmap *comp; 9278556Sobrien 9378556Sobrienstatic struct seginfo * new_seginfo (int, rtx, int, HARD_REG_SET); 9478556Sobrienstatic void add_seginfo (struct bb_info *, struct seginfo *); 9578556Sobrienstatic void reg_dies (rtx, HARD_REG_SET); 9678556Sobrienstatic void reg_becomes_live (rtx, rtx, void *); 9778556Sobrienstatic void make_preds_opaque (basic_block, int); 9878556Sobrien 9978556Sobrien 10078556Sobrien/* This function will allocate a new BBINFO structure, initialized 10178556Sobrien with the MODE, INSN, and basic block BB parameters. */ 10278556Sobrien 10378556Sobrienstatic struct seginfo * 10478556Sobriennew_seginfo (int mode, rtx insn, int bb, HARD_REG_SET regs_live) 10578556Sobrien{ 10678556Sobrien struct seginfo *ptr; 10778556Sobrien ptr = XNEW (struct seginfo); 10878556Sobrien ptr->mode = mode; 10978556Sobrien ptr->insn_ptr = insn; 11078556Sobrien ptr->bbnum = bb; 11178556Sobrien ptr->next = NULL; 11278556Sobrien COPY_HARD_REG_SET (ptr->regs_live, regs_live); 11378556Sobrien return ptr; 11478556Sobrien} 11578556Sobrien 11678556Sobrien/* Add a seginfo element to the end of a list. 11778556Sobrien HEAD is a pointer to the list beginning. 11878556Sobrien INFO is the structure to be linked in. */ 11978556Sobrien 12078556Sobrienstatic void 12178556Sobrienadd_seginfo (struct bb_info *head, struct seginfo *info) 12278556Sobrien{ 12378556Sobrien struct seginfo *ptr; 12478556Sobrien 12578556Sobrien if (head->seginfo == NULL) 12678556Sobrien head->seginfo = info; 12778556Sobrien else 12878556Sobrien { 12978556Sobrien ptr = head->seginfo; 13078556Sobrien while (ptr->next != NULL) 13178556Sobrien ptr = ptr->next; 13278556Sobrien ptr->next = info; 13378556Sobrien } 13478556Sobrien} 13578556Sobrien 13678556Sobrien/* Make all predecessors of basic block B opaque, recursively, till we hit 13778556Sobrien some that are already non-transparent, or an edge where aux is set; that 13878556Sobrien denotes that a mode set is to be done on that edge. 13978556Sobrien J is the bit number in the bitmaps that corresponds to the entity that 14078556Sobrien we are currently handling mode-switching for. */ 14178556Sobrien 14278556Sobrienstatic void 14378556Sobrienmake_preds_opaque (basic_block b, int j) 14478556Sobrien{ 14578556Sobrien edge e; 14678556Sobrien edge_iterator ei; 14778556Sobrien 14878556Sobrien FOR_EACH_EDGE (e, ei, b->preds) 14978556Sobrien { 15078556Sobrien basic_block pb = e->src; 15178556Sobrien 15278556Sobrien if (e->aux || ! TEST_BIT (transp[pb->index], j)) 15378556Sobrien continue; 15478556Sobrien 15578556Sobrien RESET_BIT (transp[pb->index], j); 15678556Sobrien make_preds_opaque (pb, j); 15778556Sobrien } 15878556Sobrien} 15978556Sobrien 16078556Sobrien/* Record in LIVE that register REG died. */ 16178556Sobrien 16278556Sobrienstatic void 16378556Sobrienreg_dies (rtx reg, HARD_REG_SET live) 16478556Sobrien{ 16578556Sobrien int regno, nregs; 16678556Sobrien 16778556Sobrien if (!REG_P (reg)) 16878556Sobrien return; 16978556Sobrien 17078556Sobrien regno = REGNO (reg); 17178556Sobrien if (regno < FIRST_PSEUDO_REGISTER) 17278556Sobrien for (nregs = hard_regno_nregs[regno][GET_MODE (reg)] - 1; nregs >= 0; 17378556Sobrien nregs--) 17478556Sobrien CLEAR_HARD_REG_BIT (live, regno + nregs); 17578556Sobrien} 17678556Sobrien 17778556Sobrien/* Record in LIVE that register REG became live. 17878556Sobrien This is called via note_stores. */ 17978556Sobrien 18078556Sobrienstatic void 18178556Sobrienreg_becomes_live (rtx reg, rtx setter ATTRIBUTE_UNUSED, void *live) 18278556Sobrien{ 18378556Sobrien int regno, nregs; 18478556Sobrien 18578556Sobrien if (GET_CODE (reg) == SUBREG) 18678556Sobrien reg = SUBREG_REG (reg); 18778556Sobrien 18878556Sobrien if (!REG_P (reg)) 18978556Sobrien return; 19078556Sobrien 19178556Sobrien regno = REGNO (reg); 19278556Sobrien if (regno < FIRST_PSEUDO_REGISTER) 19378556Sobrien for (nregs = hard_regno_nregs[regno][GET_MODE (reg)] - 1; nregs >= 0; 19478556Sobrien nregs--) 19578556Sobrien SET_HARD_REG_BIT (* (HARD_REG_SET *) live, regno + nregs); 19678556Sobrien} 19778556Sobrien 19878556Sobrien/* Make sure if MODE_ENTRY is defined the MODE_EXIT is defined 19978556Sobrien and vice versa. */ 20078556Sobrien#if defined (MODE_ENTRY) != defined (MODE_EXIT) 20178556Sobrien #error "Both MODE_ENTRY and MODE_EXIT must be defined" 20278556Sobrien#endif 20378556Sobrien 20478556Sobrien#if defined (MODE_ENTRY) && defined (MODE_EXIT) 20578556Sobrien/* Split the fallthrough edge to the exit block, so that we can note 20678556Sobrien that there NORMAL_MODE is required. Return the new block if it's 20778556Sobrien inserted before the exit block. Otherwise return null. */ 20878556Sobrien 20978556Sobrienstatic basic_block 21078556Sobriencreate_pre_exit (int n_entities, int *entity_map, const int *num_modes) 21178556Sobrien{ 21278556Sobrien edge eg; 21378556Sobrien edge_iterator ei; 21478556Sobrien basic_block pre_exit; 21578556Sobrien 21678556Sobrien /* The only non-call predecessor at this stage is a block with a 21778556Sobrien fallthrough edge; there can be at most one, but there could be 21878556Sobrien none at all, e.g. when exit is called. */ 21978556Sobrien pre_exit = 0; 22078556Sobrien FOR_EACH_EDGE (eg, ei, EXIT_BLOCK_PTR->preds) 22178556Sobrien if (eg->flags & EDGE_FALLTHRU) 22278556Sobrien { 22378556Sobrien basic_block src_bb = eg->src; 22478556Sobrien regset live_at_end = src_bb->il.rtl->global_live_at_end; 22578556Sobrien rtx last_insn, ret_reg; 22678556Sobrien 22778556Sobrien gcc_assert (!pre_exit); 22878556Sobrien /* If this function returns a value at the end, we have to 22978556Sobrien insert the final mode switch before the return value copy 23078556Sobrien to its hard register. */ 23178556Sobrien if (EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 1 23278556Sobrien && NONJUMP_INSN_P ((last_insn = BB_END (src_bb))) 23378556Sobrien && GET_CODE (PATTERN (last_insn)) == USE 23478556Sobrien && GET_CODE ((ret_reg = XEXP (PATTERN (last_insn), 0))) == REG) 23578556Sobrien { 23678556Sobrien int ret_start = REGNO (ret_reg); 23778556Sobrien int nregs = hard_regno_nregs[ret_start][GET_MODE (ret_reg)]; 23878556Sobrien int ret_end = ret_start + nregs; 23978556Sobrien int short_block = 0; 24078556Sobrien int maybe_builtin_apply = 0; 24178556Sobrien int forced_late_switch = 0; 24278556Sobrien rtx before_return_copy; 24378556Sobrien 24478556Sobrien do 24578556Sobrien { 24678556Sobrien rtx return_copy = PREV_INSN (last_insn); 24778556Sobrien rtx return_copy_pat, copy_reg; 24878556Sobrien int copy_start, copy_num; 24978556Sobrien int j; 25078556Sobrien 25178556Sobrien if (INSN_P (return_copy)) 25278556Sobrien { 25378556Sobrien if (GET_CODE (PATTERN (return_copy)) == USE 25478556Sobrien && GET_CODE (XEXP (PATTERN (return_copy), 0)) == REG 25578556Sobrien && (FUNCTION_VALUE_REGNO_P 25678556Sobrien (REGNO (XEXP (PATTERN (return_copy), 0))))) 25778556Sobrien { 25878556Sobrien maybe_builtin_apply = 1; 25978556Sobrien last_insn = return_copy; 26078556Sobrien continue; 26178556Sobrien } 26278556Sobrien /* If the return register is not (in its entirety) 26378556Sobrien likely spilled, the return copy might be 26478556Sobrien partially or completely optimized away. */ 26578556Sobrien return_copy_pat = single_set (return_copy); 26678556Sobrien if (!return_copy_pat) 26778556Sobrien { 26878556Sobrien return_copy_pat = PATTERN (return_copy); 26978556Sobrien if (GET_CODE (return_copy_pat) != CLOBBER) 27078556Sobrien break; 27178556Sobrien } 27278556Sobrien copy_reg = SET_DEST (return_copy_pat); 27378556Sobrien if (GET_CODE (copy_reg) == REG) 27478556Sobrien copy_start = REGNO (copy_reg); 27578556Sobrien else if (GET_CODE (copy_reg) == SUBREG 27678556Sobrien && GET_CODE (SUBREG_REG (copy_reg)) == REG) 27778556Sobrien copy_start = REGNO (SUBREG_REG (copy_reg)); 27878556Sobrien else 27978556Sobrien break; 28078556Sobrien if (copy_start >= FIRST_PSEUDO_REGISTER) 28178556Sobrien break; 28278556Sobrien copy_num 28378556Sobrien = hard_regno_nregs[copy_start][GET_MODE (copy_reg)]; 28478556Sobrien 28578556Sobrien /* If the return register is not likely spilled, - as is 28678556Sobrien the case for floating point on SH4 - then it might 28778556Sobrien be set by an arithmetic operation that needs a 28878556Sobrien different mode than the exit block. */ 28978556Sobrien for (j = n_entities - 1; j >= 0; j--) 29078556Sobrien { 29178556Sobrien int e = entity_map[j]; 29278556Sobrien int mode = MODE_NEEDED (e, return_copy); 29378556Sobrien 29478556Sobrien if (mode != num_modes[e] && mode != MODE_EXIT (e)) 29578556Sobrien break; 29678556Sobrien } 29778556Sobrien if (j >= 0) 29878556Sobrien { 29978556Sobrien /* For the SH4, floating point loads depend on fpscr, 30078556Sobrien thus we might need to put the final mode switch 30178556Sobrien after the return value copy. That is still OK, 30278556Sobrien because a floating point return value does not 30378556Sobrien conflict with address reloads. */ 30478556Sobrien if (copy_start >= ret_start 30578556Sobrien && copy_start + copy_num <= ret_end 30678556Sobrien && OBJECT_P (SET_SRC (return_copy_pat))) 30778556Sobrien forced_late_switch = 1; 30878556Sobrien break; 30978556Sobrien } 31078556Sobrien 31178556Sobrien if (copy_start >= ret_start 31278556Sobrien && copy_start + copy_num <= ret_end) 31378556Sobrien nregs -= copy_num; 31478556Sobrien else if (!maybe_builtin_apply 31578556Sobrien || !FUNCTION_VALUE_REGNO_P (copy_start)) 31678556Sobrien break; 31778556Sobrien last_insn = return_copy; 31878556Sobrien } 31978556Sobrien /* ??? Exception handling can lead to the return value 32078556Sobrien copy being already separated from the return value use, 32178556Sobrien as in unwind-dw2.c . 32278556Sobrien Similarly, conditionally returning without a value, 32378556Sobrien and conditionally using builtin_return can lead to an 32478556Sobrien isolated use. */ 32578556Sobrien if (return_copy == BB_HEAD (src_bb)) 32678556Sobrien { 32778556Sobrien short_block = 1; 32878556Sobrien break; 32978556Sobrien } 33078556Sobrien last_insn = return_copy; 33178556Sobrien } 33278556Sobrien while (nregs); 33378556Sobrien 33478556Sobrien /* If we didn't see a full return value copy, verify that there 33578556Sobrien is a plausible reason for this. If some, but not all of the 33678556Sobrien return register is likely spilled, we can expect that there 33778556Sobrien is a copy for the likely spilled part. */ 33878556Sobrien gcc_assert (!nregs 33978556Sobrien || forced_late_switch 34078556Sobrien || short_block 34178556Sobrien || !(CLASS_LIKELY_SPILLED_P 34278556Sobrien (REGNO_REG_CLASS (ret_start))) 34378556Sobrien || (nregs 34478556Sobrien != hard_regno_nregs[ret_start][GET_MODE (ret_reg)]) 34578556Sobrien /* For multi-hard-register floating point 34678556Sobrien values, sometimes the likely-spilled part 34778556Sobrien is ordinarily copied first, then the other 34878556Sobrien part is set with an arithmetic operation. 34978556Sobrien This doesn't actually cause reload 35078556Sobrien failures, so let it pass. */ 35178556Sobrien || (GET_MODE_CLASS (GET_MODE (ret_reg)) != MODE_INT 35278556Sobrien && nregs != 1)); 35378556Sobrien 35478556Sobrien if (INSN_P (last_insn)) 35578556Sobrien { 35678556Sobrien before_return_copy 35778556Sobrien = emit_note_before (NOTE_INSN_DELETED, last_insn); 35878556Sobrien /* Instructions preceding LAST_INSN in the same block might 35978556Sobrien require a different mode than MODE_EXIT, so if we might 36078556Sobrien have such instructions, keep them in a separate block 36178556Sobrien from pre_exit. */ 36278556Sobrien if (last_insn != BB_HEAD (src_bb)) 36378556Sobrien src_bb = split_block (src_bb, 36478556Sobrien PREV_INSN (before_return_copy))->dest; 36578556Sobrien } 36678556Sobrien else 36778556Sobrien before_return_copy = last_insn; 36878556Sobrien pre_exit = split_block (src_bb, before_return_copy)->src; 36978556Sobrien } 37078556Sobrien else 37178556Sobrien { 37278556Sobrien pre_exit = split_edge (eg); 37378556Sobrien COPY_REG_SET (pre_exit->il.rtl->global_live_at_start, live_at_end); 37478556Sobrien COPY_REG_SET (pre_exit->il.rtl->global_live_at_end, live_at_end); 37578556Sobrien } 37678556Sobrien } 37778556Sobrien 37878556Sobrien return pre_exit; 37978556Sobrien} 38078556Sobrien#endif 38178556Sobrien 38278556Sobrien/* Find all insns that need a particular mode setting, and insert the 38378556Sobrien necessary mode switches. Return true if we did work. */ 38478556Sobrien 38578556Sobrienstatic int 38678556Sobrienoptimize_mode_switching (void) 38778556Sobrien{ 38878556Sobrien rtx insn; 38978556Sobrien int e; 39078556Sobrien basic_block bb; 39178556Sobrien int need_commit = 0; 39278556Sobrien sbitmap *kill; 39378556Sobrien struct edge_list *edge_list; 39478556Sobrien static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING; 39578556Sobrien#define N_ENTITIES ARRAY_SIZE (num_modes) 39678556Sobrien int entity_map[N_ENTITIES]; 39778556Sobrien struct bb_info *bb_info[N_ENTITIES]; 39878556Sobrien int i, j; 39978556Sobrien int n_entities; 40078556Sobrien int max_num_modes = 0; 40178556Sobrien bool emited = false; 40278556Sobrien basic_block post_entry ATTRIBUTE_UNUSED, pre_exit ATTRIBUTE_UNUSED; 40378556Sobrien 40478556Sobrien clear_bb_flags (); 40578556Sobrien 40678556Sobrien for (e = N_ENTITIES - 1, n_entities = 0; e >= 0; e--) 40778556Sobrien if (OPTIMIZE_MODE_SWITCHING (e)) 40878556Sobrien { 40978556Sobrien int entry_exit_extra = 0; 41078556Sobrien 41178556Sobrien /* Create the list of segments within each basic block. 41278556Sobrien If NORMAL_MODE is defined, allow for two extra 41378556Sobrien blocks split from the entry and exit block. */ 41478556Sobrien#if defined (MODE_ENTRY) && defined (MODE_EXIT) 41578556Sobrien entry_exit_extra = 3; 41678556Sobrien#endif 41778556Sobrien bb_info[n_entities] 41878556Sobrien = XCNEWVEC (struct bb_info, last_basic_block + entry_exit_extra); 41978556Sobrien entity_map[n_entities++] = e; 42078556Sobrien if (num_modes[e] > max_num_modes) 42178556Sobrien max_num_modes = num_modes[e]; 42278556Sobrien } 42378556Sobrien 42478556Sobrien if (! n_entities) 42578556Sobrien return 0; 42678556Sobrien 42778556Sobrien#if defined (MODE_ENTRY) && defined (MODE_EXIT) 42878556Sobrien /* Split the edge from the entry block, so that we can note that 42978556Sobrien there NORMAL_MODE is supplied. */ 43078556Sobrien post_entry = split_edge (single_succ_edge (ENTRY_BLOCK_PTR)); 43178556Sobrien pre_exit = create_pre_exit (n_entities, entity_map, num_modes); 43278556Sobrien#endif 43378556Sobrien 43478556Sobrien /* Create the bitmap vectors. */ 43578556Sobrien 43678556Sobrien antic = sbitmap_vector_alloc (last_basic_block, n_entities); 43778556Sobrien transp = sbitmap_vector_alloc (last_basic_block, n_entities); 43878556Sobrien comp = sbitmap_vector_alloc (last_basic_block, n_entities); 43978556Sobrien 44078556Sobrien sbitmap_vector_ones (transp, last_basic_block); 44178556Sobrien 44278556Sobrien for (j = n_entities - 1; j >= 0; j--) 44378556Sobrien { 44478556Sobrien int e = entity_map[j]; 44578556Sobrien int no_mode = num_modes[e]; 44678556Sobrien struct bb_info *info = bb_info[j]; 447146293Sobrien 448146293Sobrien /* Determine what the first use (if any) need for a mode of entity E is. 44978556Sobrien This will be the mode that is anticipatable for this block. 45078556Sobrien Also compute the initial transparency settings. */ 451146293Sobrien FOR_EACH_BB (bb) 45278556Sobrien { 45378556Sobrien struct seginfo *ptr; 45478556Sobrien int last_mode = no_mode; 45578556Sobrien HARD_REG_SET live_now; 45678556Sobrien 45778556Sobrien REG_SET_TO_HARD_REG_SET (live_now, 45878556Sobrien bb->il.rtl->global_live_at_start); 45978556Sobrien 46078556Sobrien /* Pretend the mode is clobbered across abnormal edges. */ 46178556Sobrien { 46278556Sobrien edge_iterator ei; 46378556Sobrien edge e; 46478556Sobrien FOR_EACH_EDGE (e, ei, bb->preds) 46578556Sobrien if (e->flags & EDGE_COMPLEX) 46678556Sobrien break; 46778556Sobrien if (e) 46878556Sobrien { 46978556Sobrien ptr = new_seginfo (no_mode, BB_HEAD (bb), bb->index, live_now); 47078556Sobrien add_seginfo (info + bb->index, ptr); 47178556Sobrien RESET_BIT (transp[bb->index], j); 47278556Sobrien } 47378556Sobrien } 47478556Sobrien 47578556Sobrien for (insn = BB_HEAD (bb); 47678556Sobrien insn != NULL && insn != NEXT_INSN (BB_END (bb)); 47778556Sobrien insn = NEXT_INSN (insn)) 47878556Sobrien { 47978556Sobrien if (INSN_P (insn)) 48078556Sobrien { 48178556Sobrien int mode = MODE_NEEDED (e, insn); 48278556Sobrien rtx link; 48378556Sobrien 48478556Sobrien if (mode != no_mode && mode != last_mode) 48578556Sobrien { 48678556Sobrien last_mode = mode; 48778556Sobrien ptr = new_seginfo (mode, insn, bb->index, live_now); 488146293Sobrien add_seginfo (info + bb->index, ptr); 48978556Sobrien RESET_BIT (transp[bb->index], j); 49078556Sobrien } 49178556Sobrien#ifdef MODE_AFTER 49278556Sobrien last_mode = MODE_AFTER (last_mode, insn); 49378556Sobrien#endif 49478556Sobrien /* Update LIVE_NOW. */ 49578556Sobrien for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) 49678556Sobrien if (REG_NOTE_KIND (link) == REG_DEAD) 49778556Sobrien reg_dies (XEXP (link, 0), live_now); 49878556Sobrien 49978556Sobrien note_stores (PATTERN (insn), reg_becomes_live, &live_now); 50078556Sobrien for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) 50178556Sobrien if (REG_NOTE_KIND (link) == REG_UNUSED) 50278556Sobrien reg_dies (XEXP (link, 0), live_now); 50378556Sobrien } 50478556Sobrien } 50578556Sobrien 50678556Sobrien info[bb->index].computing = last_mode; 50778556Sobrien /* Check for blocks without ANY mode requirements. */ 50878556Sobrien if (last_mode == no_mode) 50978556Sobrien { 51078556Sobrien ptr = new_seginfo (no_mode, BB_END (bb), bb->index, live_now); 51178556Sobrien add_seginfo (info + bb->index, ptr); 51278556Sobrien } 51378556Sobrien } 51478556Sobrien#if defined (MODE_ENTRY) && defined (MODE_EXIT) 51578556Sobrien { 51678556Sobrien int mode = MODE_ENTRY (e); 51778556Sobrien 51878556Sobrien if (mode != no_mode) 51978556Sobrien { 52078556Sobrien bb = post_entry; 52178556Sobrien 52278556Sobrien /* By always making this nontransparent, we save 52378556Sobrien an extra check in make_preds_opaque. We also 52478556Sobrien need this to avoid confusing pre_edge_lcm when 52578556Sobrien antic is cleared but transp and comp are set. */ 52678556Sobrien RESET_BIT (transp[bb->index], j); 52778556Sobrien 52878556Sobrien /* Insert a fake computing definition of MODE into entry 52978556Sobrien blocks which compute no mode. This represents the mode on 53078556Sobrien entry. */ 53178556Sobrien info[bb->index].computing = mode; 53278556Sobrien 53378556Sobrien if (pre_exit) 53478556Sobrien info[pre_exit->index].seginfo->mode = MODE_EXIT (e); 53578556Sobrien } 53678556Sobrien } 53778556Sobrien#endif /* NORMAL_MODE */ 53878556Sobrien } 53978556Sobrien 54078556Sobrien kill = sbitmap_vector_alloc (last_basic_block, n_entities); 54178556Sobrien for (i = 0; i < max_num_modes; i++) 54278556Sobrien { 54378556Sobrien int current_mode[N_ENTITIES]; 54478556Sobrien sbitmap *delete; 54578556Sobrien sbitmap *insert; 54678556Sobrien 54778556Sobrien /* Set the anticipatable and computing arrays. */ 54878556Sobrien sbitmap_vector_zero (antic, last_basic_block); 54978556Sobrien sbitmap_vector_zero (comp, last_basic_block); 55078556Sobrien for (j = n_entities - 1; j >= 0; j--) 55178556Sobrien { 55278556Sobrien int m = current_mode[j] = MODE_PRIORITY_TO_MODE (entity_map[j], i); 55378556Sobrien struct bb_info *info = bb_info[j]; 55478556Sobrien 55578556Sobrien FOR_EACH_BB (bb) 55678556Sobrien { 55778556Sobrien if (info[bb->index].seginfo->mode == m) 55878556Sobrien SET_BIT (antic[bb->index], j); 55978556Sobrien 56078556Sobrien if (info[bb->index].computing == m) 56178556Sobrien SET_BIT (comp[bb->index], j); 56278556Sobrien } 56378556Sobrien } 56478556Sobrien 56578556Sobrien /* Calculate the optimal locations for the 56678556Sobrien placement mode switches to modes with priority I. */ 56778556Sobrien 56878556Sobrien FOR_EACH_BB (bb) 56978556Sobrien sbitmap_not (kill[bb->index], transp[bb->index]); 57078556Sobrien edge_list = pre_edge_lcm (n_entities, transp, comp, antic, 57178556Sobrien kill, &insert, &delete); 57278556Sobrien 57378556Sobrien for (j = n_entities - 1; j >= 0; j--) 57478556Sobrien { 57578556Sobrien /* Insert all mode sets that have been inserted by lcm. */ 57678556Sobrien int no_mode = num_modes[entity_map[j]]; 57778556Sobrien 57878556Sobrien /* Wherever we have moved a mode setting upwards in the flow graph, 57978556Sobrien the blocks between the new setting site and the now redundant 58078556Sobrien computation ceases to be transparent for any lower-priority 58178556Sobrien mode of the same entity. First set the aux field of each 58278556Sobrien insertion site edge non-transparent, then propagate the new 58378556Sobrien non-transparency from the redundant computation upwards till 58478556Sobrien we hit an insertion site or an already non-transparent block. */ 58578556Sobrien for (e = NUM_EDGES (edge_list) - 1; e >= 0; e--) 58678556Sobrien { 58778556Sobrien edge eg = INDEX_EDGE (edge_list, e); 58878556Sobrien int mode; 58978556Sobrien basic_block src_bb; 59078556Sobrien HARD_REG_SET live_at_edge; 59178556Sobrien rtx mode_set; 59278556Sobrien 59378556Sobrien eg->aux = 0; 59478556Sobrien 59578556Sobrien if (! TEST_BIT (insert[e], j)) 59678556Sobrien continue; 59778556Sobrien 59878556Sobrien eg->aux = (void *)1; 59978556Sobrien 60078556Sobrien mode = current_mode[j]; 60178556Sobrien src_bb = eg->src; 60278556Sobrien 60378556Sobrien REG_SET_TO_HARD_REG_SET (live_at_edge, 60478556Sobrien src_bb->il.rtl->global_live_at_end); 60578556Sobrien 60678556Sobrien start_sequence (); 60778556Sobrien EMIT_MODE_SET (entity_map[j], mode, live_at_edge); 60878556Sobrien mode_set = get_insns (); 60978556Sobrien end_sequence (); 61078556Sobrien 61178556Sobrien /* Do not bother to insert empty sequence. */ 612146293Sobrien if (mode_set == NULL_RTX) 613146293Sobrien continue; 61478556Sobrien 61578556Sobrien /* We should not get an abnormal edge here. */ 61678556Sobrien gcc_assert (! (eg->flags & EDGE_ABNORMAL)); 61778556Sobrien 61878556Sobrien need_commit = 1; 61978556Sobrien insert_insn_on_edge (mode_set, eg); 62078556Sobrien } 62178556Sobrien 62278556Sobrien FOR_EACH_BB_REVERSE (bb) 62378556Sobrien if (TEST_BIT (delete[bb->index], j)) 62490067Ssobomax { 62590067Ssobomax make_preds_opaque (bb, j); 62690067Ssobomax /* Cancel the 'deleted' mode set. */ 62790067Ssobomax bb_info[j][bb->index].seginfo->mode = no_mode; 62878556Sobrien } 62978556Sobrien } 63078556Sobrien 63178556Sobrien sbitmap_vector_free (delete); 63278556Sobrien sbitmap_vector_free (insert); 63378556Sobrien clear_aux_for_edges (); 63478556Sobrien free_edge_list (edge_list); 63578556Sobrien } 63678556Sobrien 63778556Sobrien /* Now output the remaining mode sets in all the segments. */ 63878556Sobrien for (j = n_entities - 1; j >= 0; j--) 63978556Sobrien { 64078556Sobrien int no_mode = num_modes[entity_map[j]]; 64178556Sobrien 64278556Sobrien FOR_EACH_BB_REVERSE (bb) 64378556Sobrien { 64478556Sobrien struct seginfo *ptr, *next; 64578556Sobrien for (ptr = bb_info[j][bb->index].seginfo; ptr; ptr = next) 64678556Sobrien { 64778556Sobrien next = ptr->next; 64878556Sobrien if (ptr->mode != no_mode) 64978556Sobrien { 65078556Sobrien rtx mode_set; 65178556Sobrien 65278556Sobrien start_sequence (); 65378556Sobrien EMIT_MODE_SET (entity_map[j], ptr->mode, ptr->regs_live); 65478556Sobrien mode_set = get_insns (); 65578556Sobrien end_sequence (); 65678556Sobrien 65778556Sobrien /* Insert MODE_SET only if it is nonempty. */ 65878556Sobrien if (mode_set != NULL_RTX) 65978556Sobrien { 66078556Sobrien emited = true; 66178556Sobrien if (NOTE_P (ptr->insn_ptr) 66278556Sobrien && (NOTE_LINE_NUMBER (ptr->insn_ptr) 66378556Sobrien == NOTE_INSN_BASIC_BLOCK)) 664146293Sobrien emit_insn_after (mode_set, ptr->insn_ptr); 66578556Sobrien else 66678556Sobrien emit_insn_before (mode_set, ptr->insn_ptr); 66778556Sobrien } 66878556Sobrien } 66978556Sobrien 67078556Sobrien free (ptr); 67178556Sobrien } 67278556Sobrien } 673 674 free (bb_info[j]); 675 } 676 677 /* Finished. Free up all the things we've allocated. */ 678 679 sbitmap_vector_free (kill); 680 sbitmap_vector_free (antic); 681 sbitmap_vector_free (transp); 682 sbitmap_vector_free (comp); 683 684 if (need_commit) 685 commit_edge_insertions (); 686 687#if defined (MODE_ENTRY) && defined (MODE_EXIT) 688 cleanup_cfg (CLEANUP_NO_INSN_DEL); 689#else 690 if (!need_commit && !emited) 691 return 0; 692#endif 693 694 max_regno = max_reg_num (); 695 allocate_reg_info (max_regno, FALSE, FALSE); 696 update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES, 697 (PROP_DEATH_NOTES | PROP_KILL_DEAD_CODE 698 | PROP_SCAN_DEAD_CODE)); 699 700 return 1; 701} 702 703#endif /* OPTIMIZE_MODE_SWITCHING */ 704 705static bool 706gate_mode_switching (void) 707{ 708#ifdef OPTIMIZE_MODE_SWITCHING 709 return true; 710#else 711 return false; 712#endif 713} 714 715static unsigned int 716rest_of_handle_mode_switching (void) 717{ 718#ifdef OPTIMIZE_MODE_SWITCHING 719 no_new_pseudos = 0; 720 optimize_mode_switching (); 721 no_new_pseudos = 1; 722#endif /* OPTIMIZE_MODE_SWITCHING */ 723 return 0; 724} 725 726 727struct tree_opt_pass pass_mode_switching = 728{ 729 "mode-sw", /* name */ 730 gate_mode_switching, /* gate */ 731 rest_of_handle_mode_switching, /* execute */ 732 NULL, /* sub */ 733 NULL, /* next */ 734 0, /* static_pass_number */ 735 TV_MODE_SWITCH, /* tv_id */ 736 0, /* properties_required */ 737 0, /* properties_provided */ 738 0, /* properties_destroyed */ 739 0, /* todo_flags_start */ 740 TODO_dump_func, /* todo_flags_finish */ 741 0 /* letter */ 742}; 743