1169689Skan/* CPU mode switching 2169689Skan Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 3169689Skan Free Software Foundation, Inc. 4169689Skan 5169689SkanThis file is part of GCC. 6169689Skan 7169689SkanGCC is free software; you can redistribute it and/or modify it under 8169689Skanthe terms of the GNU General Public License as published by the Free 9169689SkanSoftware Foundation; either version 2, or (at your option) any later 10169689Skanversion. 11169689Skan 12169689SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY 13169689SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or 14169689SkanFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15169689Skanfor more details. 16169689Skan 17169689SkanYou should have received a copy of the GNU General Public License 18169689Skanalong with GCC; see the file COPYING. If not, write to the Free 19169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 20169689Skan02110-1301, USA. */ 21169689Skan 22169689Skan#include "config.h" 23169689Skan#include "system.h" 24169689Skan#include "coretypes.h" 25169689Skan#include "tm.h" 26169689Skan#include "rtl.h" 27169689Skan#include "regs.h" 28169689Skan#include "hard-reg-set.h" 29169689Skan#include "flags.h" 30169689Skan#include "real.h" 31169689Skan#include "insn-config.h" 32169689Skan#include "recog.h" 33169689Skan#include "basic-block.h" 34169689Skan#include "output.h" 35169689Skan#include "tm_p.h" 36169689Skan#include "function.h" 37169689Skan#include "tree-pass.h" 38169689Skan#include "timevar.h" 39169689Skan 40169689Skan/* We want target macros for the mode switching code to be able to refer 41169689Skan to instruction attribute values. */ 42169689Skan#include "insn-attr.h" 43169689Skan 44169689Skan#ifdef OPTIMIZE_MODE_SWITCHING 45169689Skan 46169689Skan/* The algorithm for setting the modes consists of scanning the insn list 47169689Skan and finding all the insns which require a specific mode. Each insn gets 48169689Skan a unique struct seginfo element. These structures are inserted into a list 49169689Skan for each basic block. For each entity, there is an array of bb_info over 50169689Skan the flow graph basic blocks (local var 'bb_info'), and contains a list 51169689Skan of all insns within that basic block, in the order they are encountered. 52169689Skan 53169689Skan For each entity, any basic block WITHOUT any insns requiring a specific 54169689Skan mode are given a single entry, without a mode. (Each basic block 55169689Skan in the flow graph must have at least one entry in the segment table.) 56169689Skan 57169689Skan The LCM algorithm is then run over the flow graph to determine where to 58169689Skan place the sets to the highest-priority value in respect of first the first 59169689Skan insn in any one block. Any adjustments required to the transparency 60169689Skan vectors are made, then the next iteration starts for the next-lower 61169689Skan priority mode, till for each entity all modes are exhausted. 62169689Skan 63169689Skan More details are located in the code for optimize_mode_switching(). */ 64169689Skan 65169689Skan/* This structure contains the information for each insn which requires 66169689Skan either single or double mode to be set. 67169689Skan MODE is the mode this insn must be executed in. 68169689Skan INSN_PTR is the insn to be executed (may be the note that marks the 69169689Skan beginning of a basic block). 70169689Skan BBNUM is the flow graph basic block this insn occurs in. 71169689Skan NEXT is the next insn in the same basic block. */ 72169689Skanstruct seginfo 73169689Skan{ 74169689Skan int mode; 75169689Skan rtx insn_ptr; 76169689Skan int bbnum; 77169689Skan struct seginfo *next; 78169689Skan HARD_REG_SET regs_live; 79169689Skan}; 80169689Skan 81169689Skanstruct bb_info 82169689Skan{ 83169689Skan struct seginfo *seginfo; 84169689Skan int computing; 85169689Skan}; 86169689Skan 87169689Skan/* These bitmaps are used for the LCM algorithm. */ 88169689Skan 89169689Skanstatic sbitmap *antic; 90169689Skanstatic sbitmap *transp; 91169689Skanstatic sbitmap *comp; 92169689Skan 93169689Skanstatic struct seginfo * new_seginfo (int, rtx, int, HARD_REG_SET); 94169689Skanstatic void add_seginfo (struct bb_info *, struct seginfo *); 95169689Skanstatic void reg_dies (rtx, HARD_REG_SET); 96169689Skanstatic void reg_becomes_live (rtx, rtx, void *); 97169689Skanstatic void make_preds_opaque (basic_block, int); 98169689Skan 99169689Skan 100169689Skan/* This function will allocate a new BBINFO structure, initialized 101169689Skan with the MODE, INSN, and basic block BB parameters. */ 102169689Skan 103169689Skanstatic struct seginfo * 104169689Skannew_seginfo (int mode, rtx insn, int bb, HARD_REG_SET regs_live) 105169689Skan{ 106169689Skan struct seginfo *ptr; 107169689Skan ptr = XNEW (struct seginfo); 108169689Skan ptr->mode = mode; 109169689Skan ptr->insn_ptr = insn; 110169689Skan ptr->bbnum = bb; 111169689Skan ptr->next = NULL; 112169689Skan COPY_HARD_REG_SET (ptr->regs_live, regs_live); 113169689Skan return ptr; 114169689Skan} 115169689Skan 116169689Skan/* Add a seginfo element to the end of a list. 117169689Skan HEAD is a pointer to the list beginning. 118169689Skan INFO is the structure to be linked in. */ 119169689Skan 120169689Skanstatic void 121169689Skanadd_seginfo (struct bb_info *head, struct seginfo *info) 122169689Skan{ 123169689Skan struct seginfo *ptr; 124169689Skan 125169689Skan if (head->seginfo == NULL) 126169689Skan head->seginfo = info; 127169689Skan else 128169689Skan { 129169689Skan ptr = head->seginfo; 130169689Skan while (ptr->next != NULL) 131169689Skan ptr = ptr->next; 132169689Skan ptr->next = info; 133169689Skan } 134169689Skan} 135169689Skan 136169689Skan/* Make all predecessors of basic block B opaque, recursively, till we hit 137169689Skan some that are already non-transparent, or an edge where aux is set; that 138169689Skan denotes that a mode set is to be done on that edge. 139169689Skan J is the bit number in the bitmaps that corresponds to the entity that 140169689Skan we are currently handling mode-switching for. */ 141169689Skan 142169689Skanstatic void 143169689Skanmake_preds_opaque (basic_block b, int j) 144169689Skan{ 145169689Skan edge e; 146169689Skan edge_iterator ei; 147169689Skan 148169689Skan FOR_EACH_EDGE (e, ei, b->preds) 149169689Skan { 150169689Skan basic_block pb = e->src; 151169689Skan 152169689Skan if (e->aux || ! TEST_BIT (transp[pb->index], j)) 153169689Skan continue; 154169689Skan 155169689Skan RESET_BIT (transp[pb->index], j); 156169689Skan make_preds_opaque (pb, j); 157169689Skan } 158169689Skan} 159169689Skan 160169689Skan/* Record in LIVE that register REG died. */ 161169689Skan 162169689Skanstatic void 163169689Skanreg_dies (rtx reg, HARD_REG_SET live) 164169689Skan{ 165169689Skan int regno, nregs; 166169689Skan 167169689Skan if (!REG_P (reg)) 168169689Skan return; 169169689Skan 170169689Skan regno = REGNO (reg); 171169689Skan if (regno < FIRST_PSEUDO_REGISTER) 172169689Skan for (nregs = hard_regno_nregs[regno][GET_MODE (reg)] - 1; nregs >= 0; 173169689Skan nregs--) 174169689Skan CLEAR_HARD_REG_BIT (live, regno + nregs); 175169689Skan} 176169689Skan 177169689Skan/* Record in LIVE that register REG became live. 178169689Skan This is called via note_stores. */ 179169689Skan 180169689Skanstatic void 181169689Skanreg_becomes_live (rtx reg, rtx setter ATTRIBUTE_UNUSED, void *live) 182169689Skan{ 183169689Skan int regno, nregs; 184169689Skan 185169689Skan if (GET_CODE (reg) == SUBREG) 186169689Skan reg = SUBREG_REG (reg); 187169689Skan 188169689Skan if (!REG_P (reg)) 189169689Skan return; 190169689Skan 191169689Skan regno = REGNO (reg); 192169689Skan if (regno < FIRST_PSEUDO_REGISTER) 193169689Skan for (nregs = hard_regno_nregs[regno][GET_MODE (reg)] - 1; nregs >= 0; 194169689Skan nregs--) 195169689Skan SET_HARD_REG_BIT (* (HARD_REG_SET *) live, regno + nregs); 196169689Skan} 197169689Skan 198169689Skan/* Make sure if MODE_ENTRY is defined the MODE_EXIT is defined 199169689Skan and vice versa. */ 200169689Skan#if defined (MODE_ENTRY) != defined (MODE_EXIT) 201169689Skan #error "Both MODE_ENTRY and MODE_EXIT must be defined" 202169689Skan#endif 203169689Skan 204169689Skan#if defined (MODE_ENTRY) && defined (MODE_EXIT) 205169689Skan/* Split the fallthrough edge to the exit block, so that we can note 206169689Skan that there NORMAL_MODE is required. Return the new block if it's 207169689Skan inserted before the exit block. Otherwise return null. */ 208169689Skan 209169689Skanstatic basic_block 210169689Skancreate_pre_exit (int n_entities, int *entity_map, const int *num_modes) 211169689Skan{ 212169689Skan edge eg; 213169689Skan edge_iterator ei; 214169689Skan basic_block pre_exit; 215169689Skan 216169689Skan /* The only non-call predecessor at this stage is a block with a 217169689Skan fallthrough edge; there can be at most one, but there could be 218169689Skan none at all, e.g. when exit is called. */ 219169689Skan pre_exit = 0; 220169689Skan FOR_EACH_EDGE (eg, ei, EXIT_BLOCK_PTR->preds) 221169689Skan if (eg->flags & EDGE_FALLTHRU) 222169689Skan { 223169689Skan basic_block src_bb = eg->src; 224169689Skan regset live_at_end = src_bb->il.rtl->global_live_at_end; 225169689Skan rtx last_insn, ret_reg; 226169689Skan 227169689Skan gcc_assert (!pre_exit); 228169689Skan /* If this function returns a value at the end, we have to 229169689Skan insert the final mode switch before the return value copy 230169689Skan to its hard register. */ 231169689Skan if (EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 1 232169689Skan && NONJUMP_INSN_P ((last_insn = BB_END (src_bb))) 233169689Skan && GET_CODE (PATTERN (last_insn)) == USE 234169689Skan && GET_CODE ((ret_reg = XEXP (PATTERN (last_insn), 0))) == REG) 235169689Skan { 236169689Skan int ret_start = REGNO (ret_reg); 237169689Skan int nregs = hard_regno_nregs[ret_start][GET_MODE (ret_reg)]; 238169689Skan int ret_end = ret_start + nregs; 239169689Skan int short_block = 0; 240169689Skan int maybe_builtin_apply = 0; 241169689Skan int forced_late_switch = 0; 242169689Skan rtx before_return_copy; 243169689Skan 244169689Skan do 245169689Skan { 246169689Skan rtx return_copy = PREV_INSN (last_insn); 247169689Skan rtx return_copy_pat, copy_reg; 248169689Skan int copy_start, copy_num; 249169689Skan int j; 250169689Skan 251169689Skan if (INSN_P (return_copy)) 252169689Skan { 253169689Skan if (GET_CODE (PATTERN (return_copy)) == USE 254169689Skan && GET_CODE (XEXP (PATTERN (return_copy), 0)) == REG 255169689Skan && (FUNCTION_VALUE_REGNO_P 256169689Skan (REGNO (XEXP (PATTERN (return_copy), 0))))) 257169689Skan { 258169689Skan maybe_builtin_apply = 1; 259169689Skan last_insn = return_copy; 260169689Skan continue; 261169689Skan } 262169689Skan /* If the return register is not (in its entirety) 263169689Skan likely spilled, the return copy might be 264169689Skan partially or completely optimized away. */ 265169689Skan return_copy_pat = single_set (return_copy); 266169689Skan if (!return_copy_pat) 267169689Skan { 268169689Skan return_copy_pat = PATTERN (return_copy); 269169689Skan if (GET_CODE (return_copy_pat) != CLOBBER) 270169689Skan break; 271169689Skan } 272169689Skan copy_reg = SET_DEST (return_copy_pat); 273169689Skan if (GET_CODE (copy_reg) == REG) 274169689Skan copy_start = REGNO (copy_reg); 275169689Skan else if (GET_CODE (copy_reg) == SUBREG 276169689Skan && GET_CODE (SUBREG_REG (copy_reg)) == REG) 277169689Skan copy_start = REGNO (SUBREG_REG (copy_reg)); 278169689Skan else 279169689Skan break; 280169689Skan if (copy_start >= FIRST_PSEUDO_REGISTER) 281169689Skan break; 282169689Skan copy_num 283169689Skan = hard_regno_nregs[copy_start][GET_MODE (copy_reg)]; 284169689Skan 285169689Skan /* If the return register is not likely spilled, - as is 286169689Skan the case for floating point on SH4 - then it might 287169689Skan be set by an arithmetic operation that needs a 288169689Skan different mode than the exit block. */ 289169689Skan for (j = n_entities - 1; j >= 0; j--) 290169689Skan { 291169689Skan int e = entity_map[j]; 292169689Skan int mode = MODE_NEEDED (e, return_copy); 293169689Skan 294169689Skan if (mode != num_modes[e] && mode != MODE_EXIT (e)) 295169689Skan break; 296169689Skan } 297169689Skan if (j >= 0) 298169689Skan { 299169689Skan /* For the SH4, floating point loads depend on fpscr, 300169689Skan thus we might need to put the final mode switch 301169689Skan after the return value copy. That is still OK, 302169689Skan because a floating point return value does not 303169689Skan conflict with address reloads. */ 304169689Skan if (copy_start >= ret_start 305169689Skan && copy_start + copy_num <= ret_end 306169689Skan && OBJECT_P (SET_SRC (return_copy_pat))) 307169689Skan forced_late_switch = 1; 308169689Skan break; 309169689Skan } 310169689Skan 311169689Skan if (copy_start >= ret_start 312169689Skan && copy_start + copy_num <= ret_end) 313169689Skan nregs -= copy_num; 314169689Skan else if (!maybe_builtin_apply 315169689Skan || !FUNCTION_VALUE_REGNO_P (copy_start)) 316169689Skan break; 317169689Skan last_insn = return_copy; 318169689Skan } 319169689Skan /* ??? Exception handling can lead to the return value 320169689Skan copy being already separated from the return value use, 321169689Skan as in unwind-dw2.c . 322169689Skan Similarly, conditionally returning without a value, 323169689Skan and conditionally using builtin_return can lead to an 324169689Skan isolated use. */ 325169689Skan if (return_copy == BB_HEAD (src_bb)) 326169689Skan { 327169689Skan short_block = 1; 328169689Skan break; 329169689Skan } 330169689Skan last_insn = return_copy; 331169689Skan } 332169689Skan while (nregs); 333169689Skan 334169689Skan /* If we didn't see a full return value copy, verify that there 335169689Skan is a plausible reason for this. If some, but not all of the 336169689Skan return register is likely spilled, we can expect that there 337169689Skan is a copy for the likely spilled part. */ 338169689Skan gcc_assert (!nregs 339169689Skan || forced_late_switch 340169689Skan || short_block 341169689Skan || !(CLASS_LIKELY_SPILLED_P 342169689Skan (REGNO_REG_CLASS (ret_start))) 343169689Skan || (nregs 344169689Skan != hard_regno_nregs[ret_start][GET_MODE (ret_reg)]) 345169689Skan /* For multi-hard-register floating point 346169689Skan values, sometimes the likely-spilled part 347169689Skan is ordinarily copied first, then the other 348169689Skan part is set with an arithmetic operation. 349169689Skan This doesn't actually cause reload 350169689Skan failures, so let it pass. */ 351169689Skan || (GET_MODE_CLASS (GET_MODE (ret_reg)) != MODE_INT 352169689Skan && nregs != 1)); 353169689Skan 354169689Skan if (INSN_P (last_insn)) 355169689Skan { 356169689Skan before_return_copy 357169689Skan = emit_note_before (NOTE_INSN_DELETED, last_insn); 358169689Skan /* Instructions preceding LAST_INSN in the same block might 359169689Skan require a different mode than MODE_EXIT, so if we might 360169689Skan have such instructions, keep them in a separate block 361169689Skan from pre_exit. */ 362169689Skan if (last_insn != BB_HEAD (src_bb)) 363169689Skan src_bb = split_block (src_bb, 364169689Skan PREV_INSN (before_return_copy))->dest; 365169689Skan } 366169689Skan else 367169689Skan before_return_copy = last_insn; 368169689Skan pre_exit = split_block (src_bb, before_return_copy)->src; 369169689Skan } 370169689Skan else 371169689Skan { 372169689Skan pre_exit = split_edge (eg); 373169689Skan COPY_REG_SET (pre_exit->il.rtl->global_live_at_start, live_at_end); 374169689Skan COPY_REG_SET (pre_exit->il.rtl->global_live_at_end, live_at_end); 375169689Skan } 376169689Skan } 377169689Skan 378169689Skan return pre_exit; 379169689Skan} 380169689Skan#endif 381169689Skan 382169689Skan/* Find all insns that need a particular mode setting, and insert the 383169689Skan necessary mode switches. Return true if we did work. */ 384169689Skan 385169689Skanstatic int 386169689Skanoptimize_mode_switching (void) 387169689Skan{ 388169689Skan rtx insn; 389169689Skan int e; 390169689Skan basic_block bb; 391169689Skan int need_commit = 0; 392169689Skan sbitmap *kill; 393169689Skan struct edge_list *edge_list; 394169689Skan static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING; 395169689Skan#define N_ENTITIES ARRAY_SIZE (num_modes) 396169689Skan int entity_map[N_ENTITIES]; 397169689Skan struct bb_info *bb_info[N_ENTITIES]; 398169689Skan int i, j; 399169689Skan int n_entities; 400169689Skan int max_num_modes = 0; 401169689Skan bool emited = false; 402169689Skan basic_block post_entry ATTRIBUTE_UNUSED, pre_exit ATTRIBUTE_UNUSED; 403169689Skan 404169689Skan clear_bb_flags (); 405169689Skan 406169689Skan for (e = N_ENTITIES - 1, n_entities = 0; e >= 0; e--) 407169689Skan if (OPTIMIZE_MODE_SWITCHING (e)) 408169689Skan { 409169689Skan int entry_exit_extra = 0; 410169689Skan 411169689Skan /* Create the list of segments within each basic block. 412169689Skan If NORMAL_MODE is defined, allow for two extra 413169689Skan blocks split from the entry and exit block. */ 414169689Skan#if defined (MODE_ENTRY) && defined (MODE_EXIT) 415169689Skan entry_exit_extra = 3; 416169689Skan#endif 417169689Skan bb_info[n_entities] 418169689Skan = XCNEWVEC (struct bb_info, last_basic_block + entry_exit_extra); 419169689Skan entity_map[n_entities++] = e; 420169689Skan if (num_modes[e] > max_num_modes) 421169689Skan max_num_modes = num_modes[e]; 422169689Skan } 423169689Skan 424169689Skan if (! n_entities) 425169689Skan return 0; 426169689Skan 427169689Skan#if defined (MODE_ENTRY) && defined (MODE_EXIT) 428169689Skan /* Split the edge from the entry block, so that we can note that 429169689Skan there NORMAL_MODE is supplied. */ 430169689Skan post_entry = split_edge (single_succ_edge (ENTRY_BLOCK_PTR)); 431169689Skan pre_exit = create_pre_exit (n_entities, entity_map, num_modes); 432169689Skan#endif 433169689Skan 434169689Skan /* Create the bitmap vectors. */ 435169689Skan 436169689Skan antic = sbitmap_vector_alloc (last_basic_block, n_entities); 437169689Skan transp = sbitmap_vector_alloc (last_basic_block, n_entities); 438169689Skan comp = sbitmap_vector_alloc (last_basic_block, n_entities); 439169689Skan 440169689Skan sbitmap_vector_ones (transp, last_basic_block); 441169689Skan 442169689Skan for (j = n_entities - 1; j >= 0; j--) 443169689Skan { 444169689Skan int e = entity_map[j]; 445169689Skan int no_mode = num_modes[e]; 446169689Skan struct bb_info *info = bb_info[j]; 447169689Skan 448169689Skan /* Determine what the first use (if any) need for a mode of entity E is. 449169689Skan This will be the mode that is anticipatable for this block. 450169689Skan Also compute the initial transparency settings. */ 451169689Skan FOR_EACH_BB (bb) 452169689Skan { 453169689Skan struct seginfo *ptr; 454169689Skan int last_mode = no_mode; 455169689Skan HARD_REG_SET live_now; 456169689Skan 457169689Skan REG_SET_TO_HARD_REG_SET (live_now, 458169689Skan bb->il.rtl->global_live_at_start); 459169689Skan 460169689Skan /* Pretend the mode is clobbered across abnormal edges. */ 461169689Skan { 462169689Skan edge_iterator ei; 463169689Skan edge e; 464169689Skan FOR_EACH_EDGE (e, ei, bb->preds) 465169689Skan if (e->flags & EDGE_COMPLEX) 466169689Skan break; 467169689Skan if (e) 468169689Skan { 469169689Skan ptr = new_seginfo (no_mode, BB_HEAD (bb), bb->index, live_now); 470169689Skan add_seginfo (info + bb->index, ptr); 471169689Skan RESET_BIT (transp[bb->index], j); 472169689Skan } 473169689Skan } 474169689Skan 475169689Skan for (insn = BB_HEAD (bb); 476169689Skan insn != NULL && insn != NEXT_INSN (BB_END (bb)); 477169689Skan insn = NEXT_INSN (insn)) 478169689Skan { 479169689Skan if (INSN_P (insn)) 480169689Skan { 481169689Skan int mode = MODE_NEEDED (e, insn); 482169689Skan rtx link; 483169689Skan 484169689Skan if (mode != no_mode && mode != last_mode) 485169689Skan { 486169689Skan last_mode = mode; 487169689Skan ptr = new_seginfo (mode, insn, bb->index, live_now); 488169689Skan add_seginfo (info + bb->index, ptr); 489169689Skan RESET_BIT (transp[bb->index], j); 490169689Skan } 491169689Skan#ifdef MODE_AFTER 492169689Skan last_mode = MODE_AFTER (last_mode, insn); 493169689Skan#endif 494169689Skan /* Update LIVE_NOW. */ 495169689Skan for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) 496169689Skan if (REG_NOTE_KIND (link) == REG_DEAD) 497169689Skan reg_dies (XEXP (link, 0), live_now); 498169689Skan 499169689Skan note_stores (PATTERN (insn), reg_becomes_live, &live_now); 500169689Skan for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) 501169689Skan if (REG_NOTE_KIND (link) == REG_UNUSED) 502169689Skan reg_dies (XEXP (link, 0), live_now); 503169689Skan } 504169689Skan } 505169689Skan 506169689Skan info[bb->index].computing = last_mode; 507169689Skan /* Check for blocks without ANY mode requirements. */ 508169689Skan if (last_mode == no_mode) 509169689Skan { 510169689Skan ptr = new_seginfo (no_mode, BB_END (bb), bb->index, live_now); 511169689Skan add_seginfo (info + bb->index, ptr); 512169689Skan } 513169689Skan } 514169689Skan#if defined (MODE_ENTRY) && defined (MODE_EXIT) 515169689Skan { 516169689Skan int mode = MODE_ENTRY (e); 517169689Skan 518169689Skan if (mode != no_mode) 519169689Skan { 520169689Skan bb = post_entry; 521169689Skan 522169689Skan /* By always making this nontransparent, we save 523169689Skan an extra check in make_preds_opaque. We also 524169689Skan need this to avoid confusing pre_edge_lcm when 525169689Skan antic is cleared but transp and comp are set. */ 526169689Skan RESET_BIT (transp[bb->index], j); 527169689Skan 528169689Skan /* Insert a fake computing definition of MODE into entry 529169689Skan blocks which compute no mode. This represents the mode on 530169689Skan entry. */ 531169689Skan info[bb->index].computing = mode; 532169689Skan 533169689Skan if (pre_exit) 534169689Skan info[pre_exit->index].seginfo->mode = MODE_EXIT (e); 535169689Skan } 536169689Skan } 537169689Skan#endif /* NORMAL_MODE */ 538169689Skan } 539169689Skan 540169689Skan kill = sbitmap_vector_alloc (last_basic_block, n_entities); 541169689Skan for (i = 0; i < max_num_modes; i++) 542169689Skan { 543169689Skan int current_mode[N_ENTITIES]; 544169689Skan sbitmap *delete; 545169689Skan sbitmap *insert; 546169689Skan 547169689Skan /* Set the anticipatable and computing arrays. */ 548169689Skan sbitmap_vector_zero (antic, last_basic_block); 549169689Skan sbitmap_vector_zero (comp, last_basic_block); 550169689Skan for (j = n_entities - 1; j >= 0; j--) 551169689Skan { 552169689Skan int m = current_mode[j] = MODE_PRIORITY_TO_MODE (entity_map[j], i); 553169689Skan struct bb_info *info = bb_info[j]; 554169689Skan 555169689Skan FOR_EACH_BB (bb) 556169689Skan { 557169689Skan if (info[bb->index].seginfo->mode == m) 558169689Skan SET_BIT (antic[bb->index], j); 559169689Skan 560169689Skan if (info[bb->index].computing == m) 561169689Skan SET_BIT (comp[bb->index], j); 562169689Skan } 563169689Skan } 564169689Skan 565169689Skan /* Calculate the optimal locations for the 566169689Skan placement mode switches to modes with priority I. */ 567169689Skan 568169689Skan FOR_EACH_BB (bb) 569169689Skan sbitmap_not (kill[bb->index], transp[bb->index]); 570169689Skan edge_list = pre_edge_lcm (n_entities, transp, comp, antic, 571169689Skan kill, &insert, &delete); 572169689Skan 573169689Skan for (j = n_entities - 1; j >= 0; j--) 574169689Skan { 575169689Skan /* Insert all mode sets that have been inserted by lcm. */ 576169689Skan int no_mode = num_modes[entity_map[j]]; 577169689Skan 578169689Skan /* Wherever we have moved a mode setting upwards in the flow graph, 579169689Skan the blocks between the new setting site and the now redundant 580169689Skan computation ceases to be transparent for any lower-priority 581169689Skan mode of the same entity. First set the aux field of each 582169689Skan insertion site edge non-transparent, then propagate the new 583169689Skan non-transparency from the redundant computation upwards till 584169689Skan we hit an insertion site or an already non-transparent block. */ 585169689Skan for (e = NUM_EDGES (edge_list) - 1; e >= 0; e--) 586169689Skan { 587169689Skan edge eg = INDEX_EDGE (edge_list, e); 588169689Skan int mode; 589169689Skan basic_block src_bb; 590169689Skan HARD_REG_SET live_at_edge; 591169689Skan rtx mode_set; 592169689Skan 593169689Skan eg->aux = 0; 594169689Skan 595169689Skan if (! TEST_BIT (insert[e], j)) 596169689Skan continue; 597169689Skan 598169689Skan eg->aux = (void *)1; 599169689Skan 600169689Skan mode = current_mode[j]; 601169689Skan src_bb = eg->src; 602169689Skan 603169689Skan REG_SET_TO_HARD_REG_SET (live_at_edge, 604169689Skan src_bb->il.rtl->global_live_at_end); 605169689Skan 606169689Skan start_sequence (); 607169689Skan EMIT_MODE_SET (entity_map[j], mode, live_at_edge); 608169689Skan mode_set = get_insns (); 609169689Skan end_sequence (); 610169689Skan 611169689Skan /* Do not bother to insert empty sequence. */ 612169689Skan if (mode_set == NULL_RTX) 613169689Skan continue; 614169689Skan 615169689Skan /* We should not get an abnormal edge here. */ 616169689Skan gcc_assert (! (eg->flags & EDGE_ABNORMAL)); 617169689Skan 618169689Skan need_commit = 1; 619169689Skan insert_insn_on_edge (mode_set, eg); 620169689Skan } 621169689Skan 622169689Skan FOR_EACH_BB_REVERSE (bb) 623169689Skan if (TEST_BIT (delete[bb->index], j)) 624169689Skan { 625169689Skan make_preds_opaque (bb, j); 626169689Skan /* Cancel the 'deleted' mode set. */ 627169689Skan bb_info[j][bb->index].seginfo->mode = no_mode; 628169689Skan } 629169689Skan } 630169689Skan 631169689Skan sbitmap_vector_free (delete); 632169689Skan sbitmap_vector_free (insert); 633169689Skan clear_aux_for_edges (); 634169689Skan free_edge_list (edge_list); 635169689Skan } 636169689Skan 637169689Skan /* Now output the remaining mode sets in all the segments. */ 638169689Skan for (j = n_entities - 1; j >= 0; j--) 639169689Skan { 640169689Skan int no_mode = num_modes[entity_map[j]]; 641169689Skan 642169689Skan FOR_EACH_BB_REVERSE (bb) 643169689Skan { 644169689Skan struct seginfo *ptr, *next; 645169689Skan for (ptr = bb_info[j][bb->index].seginfo; ptr; ptr = next) 646169689Skan { 647169689Skan next = ptr->next; 648169689Skan if (ptr->mode != no_mode) 649169689Skan { 650169689Skan rtx mode_set; 651169689Skan 652169689Skan start_sequence (); 653169689Skan EMIT_MODE_SET (entity_map[j], ptr->mode, ptr->regs_live); 654169689Skan mode_set = get_insns (); 655169689Skan end_sequence (); 656169689Skan 657169689Skan /* Insert MODE_SET only if it is nonempty. */ 658169689Skan if (mode_set != NULL_RTX) 659169689Skan { 660169689Skan emited = true; 661169689Skan if (NOTE_P (ptr->insn_ptr) 662169689Skan && (NOTE_LINE_NUMBER (ptr->insn_ptr) 663169689Skan == NOTE_INSN_BASIC_BLOCK)) 664169689Skan emit_insn_after (mode_set, ptr->insn_ptr); 665169689Skan else 666169689Skan emit_insn_before (mode_set, ptr->insn_ptr); 667169689Skan } 668169689Skan } 669169689Skan 670169689Skan free (ptr); 671169689Skan } 672169689Skan } 673169689Skan 674169689Skan free (bb_info[j]); 675169689Skan } 676169689Skan 677169689Skan /* Finished. Free up all the things we've allocated. */ 678169689Skan 679169689Skan sbitmap_vector_free (kill); 680169689Skan sbitmap_vector_free (antic); 681169689Skan sbitmap_vector_free (transp); 682169689Skan sbitmap_vector_free (comp); 683169689Skan 684169689Skan if (need_commit) 685169689Skan commit_edge_insertions (); 686169689Skan 687169689Skan#if defined (MODE_ENTRY) && defined (MODE_EXIT) 688169689Skan cleanup_cfg (CLEANUP_NO_INSN_DEL); 689169689Skan#else 690169689Skan if (!need_commit && !emited) 691169689Skan return 0; 692169689Skan#endif 693169689Skan 694169689Skan max_regno = max_reg_num (); 695169689Skan allocate_reg_info (max_regno, FALSE, FALSE); 696169689Skan update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES, 697169689Skan (PROP_DEATH_NOTES | PROP_KILL_DEAD_CODE 698169689Skan | PROP_SCAN_DEAD_CODE)); 699169689Skan 700169689Skan return 1; 701169689Skan} 702169689Skan 703169689Skan#endif /* OPTIMIZE_MODE_SWITCHING */ 704169689Skan 705169689Skanstatic bool 706169689Skangate_mode_switching (void) 707169689Skan{ 708169689Skan#ifdef OPTIMIZE_MODE_SWITCHING 709169689Skan return true; 710169689Skan#else 711169689Skan return false; 712169689Skan#endif 713169689Skan} 714169689Skan 715169689Skanstatic unsigned int 716169689Skanrest_of_handle_mode_switching (void) 717169689Skan{ 718169689Skan#ifdef OPTIMIZE_MODE_SWITCHING 719169689Skan no_new_pseudos = 0; 720169689Skan optimize_mode_switching (); 721169689Skan no_new_pseudos = 1; 722169689Skan#endif /* OPTIMIZE_MODE_SWITCHING */ 723169689Skan return 0; 724169689Skan} 725169689Skan 726169689Skan 727169689Skanstruct tree_opt_pass pass_mode_switching = 728169689Skan{ 729169689Skan "mode-sw", /* name */ 730169689Skan gate_mode_switching, /* gate */ 731169689Skan rest_of_handle_mode_switching, /* execute */ 732169689Skan NULL, /* sub */ 733169689Skan NULL, /* next */ 734169689Skan 0, /* static_pass_number */ 735169689Skan TV_MODE_SWITCH, /* tv_id */ 736169689Skan 0, /* properties_required */ 737169689Skan 0, /* properties_provided */ 738169689Skan 0, /* properties_destroyed */ 739169689Skan 0, /* todo_flags_start */ 740169689Skan TODO_dump_func, /* todo_flags_finish */ 741169689Skan 0 /* letter */ 742169689Skan}; 743