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