This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] support to flip modes in sh mode-switching


Thank you for your comments. The first version of this patch was indeed quite immature. Here is a version that fixes the mentioned issues. Also it fixes the handling of multiple entities that I didn't take into account initially.

The bugzilla entry I was referring to is http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29349
(sorry for the typo)


- as you suggested, I removed the new edge field hook to hold the mode value attached to each edge. But I had to add a little bit of extra code to handle the mapping edge-modes and to create edge indexes. If in the future a new auxiliary field is added into the edge structure for other reasons we should remember to take the opportunity to update the mode-switching implementation.

- avin and avout allocation that were before allocated/freed at each iteration because hidden inside pre_edge_lcm at are now hoisted out of the loop. The pre_edge_lcm is now a wrapper to pre_edge_lcm_avs to allow other phases to remain unmodified. Only avin is actually needed.

- I finally use an extended version of EMIT_MODE_SET instead of creating a new macro EMIT_MODE_SWITCH in order not to complexity the code at the call sites.

bootstraped and check-gcc on i386-linux
check-gcc on sh-superh-elf -m4-300

Hoping that this patch can be incorporated into the trunk,

Best Regards

Christian

	
	* basic-block.h (pre_edge_lcm_avs): Declare
	* config/i386/i386.h (EMIT_MODE_SET): Add ACTUALMODE parameter.
	* doc/tm.texi (EMIT_MODE_SET): Item.
	* config/i386/sh.h (EMIT_MODE_SET): Item. Call emit_fpu_flip if
	ACTUALMODE is known
	* config/sh/sh-protos.h	(emit_fpu_flip): Add proto.
	* config/sh/sh.c (emit_fpu_flip): New function.
	* config/sh/sh.md (toggle_pr): Defined for TARGET_SH4_300 instead.
	Defined if TARGET_FPU_SINGLE.
	* lcm.c (pre_edge_lcm_avs): Renamed from pre_edge_lcm.
	(pre_edge_lcm): New function to allocate avin/avout and
	call pre_edge_lcm.
	* mode-switching.c (init_edge_list): New function.
	(compute_edge_index): Idem.
	(init_mode_info): Idem.
	(add_mode_set): Idem.
	(add_mode_prev_set): Idem.
	(get_mode): Idem.
	(get_prev_mode): Idem.
	(free_mode_info): Idem.
	(commit_mode_sets): Idem.
	(known_mode): Idem.
	(set_edge_modes_internal): Idem.
	(set_edge_modes): Idem.
	(optimize_mode_switching): Propagates modes on edge and handle
	mode flipping.
	(struct mode_info): New struct.
	
Steven Bosscher wrote:
On Friday 15 December 2006 17:26, Christian BRUEL wrote:

The problem was described by Joern Rennecke in bugzilla #29439 (part 3).


I'm afraid it was not, because that bug is a VRP problem.
Got the correct bug number?


1) In order to add this mode information on edges, I added an 'aux2' in
the edge_def struct. The alternatives could have been:
 - use the already existing 'aux' field. But it is broken by
pre_edge_lcm and the cost of saving restoring it might be high (vector
or size #of edges * # of entities).
 - have a local edge vector. but that seems redundant.

there is a also ann additional memory cost for other targets.


And a rather high one, too.

You're proposing to have an aux2 field on _every_ edge for _every_
target, when we're trying to reduce memory consumption instead of
increasing it again...

I think this aux2 field is simply unacceptable.



2) the EMIT_MODE_SET macro was extended with a new parameter that is the
actual mode, when known, or -1.
after rethought, I would prefer to have a new macro, EMIT_MODE_SWITCH
that seems closer to the semantic. This macro could be use to #undef
code, such as the 'aux2' field in edge_def.


You can't #undef that, edge_def is in GC space, and gengtype does
not grok #ifdefs in structures.



the other local changes to mode-switching.c are
- avin is now a parameter to pre_edge_lcm


I really dislike this, because you allocate and then free the bitmap
in most of the passes without ever looking at it.  I see you need it
in mode-switching.c but you don't explain why.

(In fact you don't explain at all what this patch does).

You also don't update the comment before lcm.c:pre_edge_lcm.

It seems to me that you could do all of this a lot cleaner if you
factor out the compute_available call out of pre_edge_lcm (and of
its reverse CFG counterpart).  Just compute the avail bitmaps
explicitly in all places and call the LCM routines after that.



- EMIT_MODE_SET is now called lazily, since the insertion should wait
for all modes to be processed and value know before emitting the rtl.

validated it on sh4-300 with gcc testsuite.


Bootstrapped on some native target, too?



+static void
+init_mode_sets (void)
+{
+  struct edge_list* edge_list = create_edge_list ();
+  int n = NUM_EDGES (edge_list);
+
+  edge_mode_inserts = xcalloc (n, sizeof (int));
+  memset (edge_mode_inserts, -1, n * sizeof (int));
+}


Why xcalloc something, and then memset it to something else?



+init_edge_auxes (int n_entities)
+{
+  basic_block bb;
+
+  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)


You can use FOR_ALL_BB here. Likewise in free_edge_auxes.



+ ((int *)e->aux2)[j] = ((int *)e2->aux2)[j];


I'd very much prefer you introduce a macro somewhere instead of
these explicit casts all over.


+ set_edge_modes_internal(cfun->cfg->x_entry_block_ptr->next_bb, visited, info, j, no_mode);


Line too long. Also, why not just ENTRY_BLOCK_PTR->next_bb?

You have no comments before most functions, so it's impossible to
tell what you've tried to implement and review that.  There are
also lots of little coding style issues.

You may want to read http://gcc.gnu.org/codingconventions.html
and http://gcc.gnu.org/contribute.html#patches if you have not
already done so.

Gr.
Steven



diff -rcp gcc-4.3-20061216/gcc/basic-block.h gcc-4.3-20061216.mode-switch/gcc/basic-block.h
*** gcc-4.3-20061216/gcc/basic-block.h	2006-11-25 11:34:13.000000000 +0100
--- gcc-4.3-20061216.mode-switch/gcc/basic-block.h	2006-12-19 15:18:36.000000000 +0100
*************** extern void free_propagate_block_info (s
*** 863,868 ****
--- 863,871 ----
  extern struct edge_list *pre_edge_lcm (int, sbitmap *, sbitmap *,
  				       sbitmap *, sbitmap *, sbitmap **,
  				       sbitmap **);
+ extern struct edge_list *pre_edge_lcm_avs (int, sbitmap *, sbitmap *,
+ 					   sbitmap *, sbitmap *, sbitmap *,
+ 					   sbitmap *, sbitmap **, sbitmap **);
  extern struct edge_list *pre_edge_rev_lcm (int, sbitmap *,
  					   sbitmap *, sbitmap *,
  					   sbitmap *, sbitmap **,
diff -rcp gcc-4.3-20061216/gcc/config/i386/i386.h gcc-4.3-20061216.mode-switch/gcc/config/i386/i386.h
*** gcc-4.3-20061216/gcc/config/i386/i386.h	2006-12-13 19:07:47.000000000 +0100
--- gcc-4.3-20061216.mode-switch/gcc/config/i386/i386.h	2006-12-18 16:14:11.000000000 +0100
*************** enum ix86_stack_slot
*** 2246,2252 ****
     is the set of hard registers live at the point where the insn(s)
     are to be inserted.  */
  
! #define EMIT_MODE_SET(ENTITY, MODE, HARD_REGS_LIVE) 			\
    ((MODE) != I387_CW_ANY && (MODE) != I387_CW_UNINITIALIZED		\
     ? emit_i387_cw_initialization (MODE), 0				\
     : 0)
--- 2246,2252 ----
     is the set of hard registers live at the point where the insn(s)
     are to be inserted.  */
  
! #define EMIT_MODE_SET(ENTITY, MODE, ACTUALMODE, HARD_REGS_LIVE)		\
    ((MODE) != I387_CW_ANY && (MODE) != I387_CW_UNINITIALIZED		\
     ? emit_i387_cw_initialization (MODE), 0				\
     : 0)
diff -rcp gcc-4.3-20061216/gcc/config/sh/sh.c gcc-4.3-20061216.mode-switch/gcc/config/sh/sh.c
*** gcc-4.3-20061216/gcc/config/sh/sh.c	2006-12-05 18:26:05.000000000 +0100
--- gcc-4.3-20061216.mode-switch/gcc/config/sh/sh.c	2006-12-19 09:15:26.000000000 +0100
*************** get_free_reg (HARD_REG_SET regs_live)
*** 8524,8529 ****
--- 8524,8537 ----
    return gen_rtx_REG (Pmode, 7);
  }
  
+ /* This function switches the fpscr.
+    MODE is the mode we are setting it to.  */
+ void
+ emit_fpu_flip (void)
+ {
+   emit_insn (gen_toggle_pr ());
+ }
+ 
  /* This function will set the fpscr from memory.
     MODE is the mode we are setting it to.  */
  void
diff -rcp gcc-4.3-20061216/gcc/config/sh/sh.h gcc-4.3-20061216.mode-switch/gcc/config/sh/sh.h
*** gcc-4.3-20061216/gcc/config/sh/sh.h	2006-12-08 17:37:42.000000000 +0100
--- gcc-4.3-20061216.mode-switch/gcc/config/sh/sh.h	2006-12-19 09:04:22.000000000 +0100
*************** extern int current_function_interrupt;
*** 3418,3425 ****
  #define MODE_PRIORITY_TO_MODE(ENTITY, N) \
    ((TARGET_FPU_SINGLE != 0) ^ (N) ? FP_MODE_SINGLE : FP_MODE_DOUBLE)
  
! #define EMIT_MODE_SET(ENTITY, MODE, HARD_REGS_LIVE) \
!   fpscr_set_from_mem ((MODE), (HARD_REGS_LIVE))
  
  #define MD_CAN_REDIRECT_BRANCH(INSN, SEQ) \
    sh_can_redirect_branch ((INSN), (SEQ))
--- 3418,3428 ----
  #define MODE_PRIORITY_TO_MODE(ENTITY, N) \
    ((TARGET_FPU_SINGLE != 0) ^ (N) ? FP_MODE_SINGLE : FP_MODE_DOUBLE)
  
! #define EMIT_MODE_SET(ENTITY, MODE, ACTUALMODE, HARD_REGS_LIVE) \
!   ((TARGET_SH4A_FP || TARGET_SH4_300)   \
!    && (ACTUALMODE) != -1                \
!    ? emit_fpu_flip ()                   \
!    : fpscr_set_from_mem ((MODE), (HARD_REGS_LIVE)))
  
  #define MD_CAN_REDIRECT_BRANCH(INSN, SEQ) \
    sh_can_redirect_branch ((INSN), (SEQ))
diff -rcp gcc-4.3-20061216/gcc/config/sh/sh.md gcc-4.3-20061216.mode-switch/gcc/config/sh/sh.md
*** gcc-4.3-20061216/gcc/config/sh/sh.md	2006-11-29 15:35:38.000000000 +0100
--- gcc-4.3-20061216.mode-switch/gcc/config/sh/sh.md	2006-12-19 14:30:01.000000000 +0100
*************** mov.l\\t1f,r0\\n\\
*** 10066,10080 ****
    "fschg"
    [(set_attr "type" "fpscr_toggle") (set_attr "fp_set" "unknown")])
  
- ;; There's no way we can use it today, since optimize mode switching
- ;; doesn't enable us to know from which mode we're switching to the
- ;; mode it requests, to tell whether we can use a relative mode switch
- ;; (like toggle_pr) or an absolute switch (like loading fpscr from
- ;; memory).
  (define_insn "toggle_pr"
    [(set (reg:PSI FPSCR_REG)
  	(xor:PSI (reg:PSI FPSCR_REG) (const_int 524288)))]
!   "TARGET_SH4A_FP && ! TARGET_FPU_SINGLE"
    "fpchg"
    [(set_attr "type" "fpscr_toggle")])
  
--- 10066,10075 ----
    "fschg"
    [(set_attr "type" "fpscr_toggle") (set_attr "fp_set" "unknown")])
  
  (define_insn "toggle_pr"
    [(set (reg:PSI FPSCR_REG)
  	(xor:PSI (reg:PSI FPSCR_REG) (const_int 524288)))]
!   "(TARGET_SH4A_FP || TARGET_SH4_300)"
    "fpchg"
    [(set_attr "type" "fpscr_toggle")])
  
diff -rcp gcc-4.3-20061216/gcc/config/sh/sh-protos.h gcc-4.3-20061216.mode-switch/gcc/config/sh/sh-protos.h
*** gcc-4.3-20061216/gcc/config/sh/sh-protos.h	2006-11-03 15:52:19.000000000 +0100
--- gcc-4.3-20061216.mode-switch/gcc/config/sh/sh-protos.h	2006-12-18 16:13:12.000000000 +0100
*************** extern int check_use_sfunc_addr (rtx, rt
*** 151,156 ****
--- 151,157 ----
  #ifdef HARD_CONST
  extern void fpscr_set_from_mem (int, HARD_REG_SET);
  #endif
+ extern void emit_fpu_flip (void);
  
  extern void sh_pr_interrupt (struct cpp_reader *);
  extern void sh_pr_trapa (struct cpp_reader *);
diff -rcp gcc-4.3-20061216/gcc/doc/tm.texi gcc-4.3-20061216.mode-switch/gcc/doc/tm.texi
*** gcc-4.3-20061216/gcc/doc/tm.texi	2006-12-13 00:53:37.000000000 +0100
--- gcc-4.3-20061216.mode-switch/gcc/doc/tm.texi	2006-12-19 09:05:10.000000000 +0100
*************** for @var{entity}.  For any fixed @var{en
*** 8833,8842 ****
  @code{num_modes_for_mode_switching[@var{entity}] - 1}.
  @end defmac
  
! @defmac EMIT_MODE_SET (@var{entity}, @var{mode}, @var{hard_regs_live})
  Generate one or more insns to set @var{entity} to @var{mode}.
  @var{hard_reg_live} is the set of hard registers live at the point where
! the insn(s) are to be inserted.
  @end defmac
  
  @node Target Attributes
--- 8833,8842 ----
  @code{num_modes_for_mode_switching[@var{entity}] - 1}.
  @end defmac
  
! @defmac EMIT_MODE_SET (@var{entity}, @var{mode}, @var{actualmode}, @var{hard_regs_live})
  Generate one or more insns to set @var{entity} to @var{mode}.
  @var{hard_reg_live} is the set of hard registers live at the point where
! the insn(s) are to be inserted. @var{actualmode} is the mode for which the entity is already set.
  @end defmac
  
  @node Target Attributes
diff -rcp gcc-4.3-20061216/gcc/lcm.c gcc-4.3-20061216.mode-switch/gcc/lcm.c
*** gcc-4.3-20061216/gcc/lcm.c	2006-02-06 19:20:47.000000000 +0100
--- gcc-4.3-20061216.mode-switch/gcc/lcm.c	2006-12-19 09:11:09.000000000 +0100
*************** compute_insert_delete (struct edge_list 
*** 371,387 ****
      }
  }
  
  /* Given local properties TRANSP, ANTLOC, AVOUT, KILL return the insert and
     delete vectors for edge based LCM.  Returns an edgelist which is used to
     map the insert vector to what edge an expression should be inserted on.  */
  
  struct edge_list *
! pre_edge_lcm (int n_exprs, sbitmap *transp,
! 	      sbitmap *avloc, sbitmap *antloc, sbitmap *kill,
! 	      sbitmap **insert, sbitmap **delete)
  {
    sbitmap *antin, *antout, *earliest;
-   sbitmap *avin, *avout;
    sbitmap *later, *laterin;
    struct edge_list *edge_list;
    int num_edges;
--- 371,408 ----
      }
  }
  
+ struct edge_list *
+ pre_edge_lcm (int n_exprs, sbitmap *transp,
+ 	      sbitmap *avloc, sbitmap *antloc, sbitmap *kill, 
+ 	      sbitmap **insert, sbitmap **delete)
+ {
+   struct edge_list *edge_list;
+   sbitmap *avin, *avout;
+ 
+   avin = sbitmap_vector_alloc (last_basic_block, n_exprs);
+   avout = sbitmap_vector_alloc (last_basic_block, n_exprs);
+ 
+   edge_list = pre_edge_lcm_avs (n_exprs, transp, avloc, antloc, kill,
+ 				 avin, avout, insert, delete);
+ 
+   sbitmap_vector_free (avout);
+   sbitmap_vector_free (avin);
+ 
+   return edge_list;
+ }
+ 
+ 
  /* Given local properties TRANSP, ANTLOC, AVOUT, KILL return the insert and
     delete vectors for edge based LCM.  Returns an edgelist which is used to
     map the insert vector to what edge an expression should be inserted on.  */
  
  struct edge_list *
! pre_edge_lcm_avs (int n_exprs, sbitmap *transp,
! 		   sbitmap *avloc, sbitmap *antloc, sbitmap *kill,
! 		   sbitmap *avin, sbitmap *avout,
! 		  sbitmap **insert, sbitmap **delete)
  {
    sbitmap *antin, *antout, *earliest;
    sbitmap *later, *laterin;
    struct edge_list *edge_list;
    int num_edges;
*************** pre_edge_lcm (int n_exprs, sbitmap *tran
*** 403,412 ****
  #endif
  
    /* Compute global availability.  */
-   avin = sbitmap_vector_alloc (last_basic_block, n_exprs);
-   avout = sbitmap_vector_alloc (last_basic_block, n_exprs);
    compute_available (avloc, kill, avout, avin);
-   sbitmap_vector_free (avin);
  
    /* Compute global anticipatability.  */
    antin = sbitmap_vector_alloc (last_basic_block, n_exprs);
--- 424,430 ----
*************** pre_edge_lcm (int n_exprs, sbitmap *tran
*** 432,438 ****
  
    sbitmap_vector_free (antout);
    sbitmap_vector_free (antin);
-   sbitmap_vector_free (avout);
  
    later = sbitmap_vector_alloc (num_edges, n_exprs);
  
--- 450,455 ----
diff -rcp gcc-4.3-20061216/gcc/mode-switching.c gcc-4.3-20061216.mode-switch/gcc/mode-switching.c
*** gcc-4.3-20061216/gcc/mode-switching.c	2006-09-05 23:41:23.000000000 +0200
--- gcc-4.3-20061216.mode-switch/gcc/mode-switching.c	2006-12-19 10:41:40.000000000 +0100
*************** struct bb_info
*** 84,89 ****
--- 84,245 ----
    int computing;
  };
  
+ static struct edge_list* edge_list;
+ static int num_edges;
+ 
+ /* We are missing the edge_to_index mapping. Maintain one here.
+    We need it in order to attach the mode information to edges. I could use edge->aux 
+    unfortunatly it is also used in pre_edge_lcm.  */
+ 
+ static void
+ init_edge_list (void)
+ {
+   edge_list = create_edge_list ();
+   num_edges = NUM_EDGES (edge_list);
+ }
+ 
+ /* Like find_edge_index, but without the basic_blocks. 
+    Used to create unique edge numbers. the control flow is not modified during
+    this phase, so edge_list remains constant and can be allocated once. */
+ 
+ static int
+ compute_edge_index (edge e)
+ {
+   int x;
+ 
+   for (x = 0; x < num_edges; x++)
+     if (edge_list->index_to_edge[x] == e)
+       return x;
+ 
+   return (EDGE_INDEX_NO_EDGE);
+ }
+ 
+ /* To support mode switching, the algorithm cannot set the modes after
+    the insert and delete bitmaps are computed by pre_edge_lcm, because 'avin' is
+    computed iteratively for each possible modes for each entity.
+    Mode emission will be done after all mode are processed. (see commit_mode_sets).
+    The struct mode_info is used to carry edge informations.  */
+ 
+ /* Indicates that edge mode information is unknown. Cannot use 'no_mode'
+    because its value depends of its entity */
+ 
+ #define NO_MODE -1
+ 
+ struct mode_info
+ {
+   int *needed;   /* mode to be inserted */
+   int *prev;     /* value of known mode, or -1 if unknown */
+ };
+ 
+ static struct mode_info *edge_mode_info;
+ 
+ static void
+ init_mode_info (int n_entities)
+ {
+   edge_mode_info = xcalloc (n_entities, sizeof (struct mode_info));
+ }
+ 
+ static void
+ add_mode_set (int j, int e, int mode)
+ {
+   if (! edge_mode_info[j].needed)
+     {
+       edge_mode_info[j].needed = xmalloc (num_edges * sizeof (int));
+       memset (edge_mode_info[j].needed, NO_MODE, num_edges * sizeof (int));
+     }
+ 
+   edge_mode_info[j].needed[e] = mode;
+ }
+ 
+ static void
+ add_mode_prev_set (int j, int e, int mode)
+ {
+   if (! edge_mode_info[j].prev)
+     {
+       edge_mode_info[j].prev = xmalloc (num_edges * sizeof (int));
+       memset (edge_mode_info[j].prev, NO_MODE, num_edges * sizeof (int));
+     }
+ 
+   edge_mode_info[j].prev[e] = mode;
+ }
+ 
+ static int
+ get_mode (int j, int e)
+ {
+   if (edge_mode_info[j].needed == NULL)
+     return NO_MODE;
+ 
+   return edge_mode_info[j].needed[e];
+ }
+ 
+ static int
+ get_prev_mode (int j, int e)
+ {
+   if (edge_mode_info[j].prev == NULL)
+     return NO_MODE;
+ 
+   return edge_mode_info[j].prev[e];
+ }
+ 
+ static void
+ free_mode_info (int n_entities)
+ {
+   int j;
+ 
+   for (j = n_entities - 1; j >= 0; j--)
+     {
+       if (edge_mode_info[j].needed != NULL)
+ 	free (edge_mode_info[j].needed);
+       if (edge_mode_info[j].prev != NULL)
+ 	free (edge_mode_info[j].prev);
+     }
+ }
+ 
+ static int
+ commit_mode_sets (int j)
+ {
+   int need_commit = 0;
+   int e;
+ 
+   if (edge_mode_info[j].needed == NULL)
+     return 0;
+ 
+   for (e = 0; e < num_edges; e++)
+     {
+       HARD_REG_SET live_at_edge;
+       edge eg = INDEX_EDGE (edge_list, e);
+       basic_block src_bb = eg->src;
+       int mode, prev_mode;
+       rtx mode_set;
+ 
+       if ((mode = get_mode (j, e)) == NO_MODE)
+ 	continue;
+ 
+       prev_mode = get_prev_mode (j, e);
+ 
+       REG_SET_TO_HARD_REG_SET (live_at_edge, src_bb->il.rtl->global_live_at_end);
+ 
+       start_sequence ();
+       EMIT_MODE_SET (entity_map[j], mode, prev_mode, live_at_edge);
+ 
+       mode_set = get_insns ();
+       end_sequence ();      
+ 
+       /* Do not bother to insert empty sequence.  */
+       if (mode_set == NULL_RTX)
+ 	continue;
+ 
+       /* We should not get an abnormal edge here.  */
+       gcc_assert (! (eg->flags & EDGE_ABNORMAL));
+ 	  
+       need_commit = 1;
+       insert_insn_on_edge (mode_set, eg);
+     }
+ 
+   return need_commit;
+ }
+ 
+ 
  /* These bitmaps are used for the LCM algorithm.  */
  
  static sbitmap *antic;
*************** create_pre_exit (int n_entities, int *en
*** 379,384 ****
--- 535,602 ----
  }
  #endif
  
+ /* Returns mode for which bb is set when entering. Or NO_MODE if 
+    modes from incoming edges differ.  */
+ 
+ static int
+ known_mode (basic_block bb, int j)
+ {
+   edge_iterator ei;
+   edge e;  
+   int mode = -2;
+ 
+   FOR_EACH_EDGE (e, ei, bb->preds)
+     {
+       if (mode == -2)
+ 	mode = get_prev_mode (j, compute_edge_index (e));
+       else if (mode != get_prev_mode (j, compute_edge_index (e)))
+ 	{
+ 	  mode = NO_MODE;
+ 	  break;
+ 	}
+     }
+ 
+   return mode;
+ }
+ 
+ /* These two functions perform a depth first propagation of computed modes
+    and sets the mode_info for each edge.  */
+ 
+ static void
+ set_edge_modes_internal (basic_block bb, sbitmap visited,
+ 			 struct bb_info *info, int j, int no_mode)
+ {
+   edge_iterator ei;
+   edge e;  
+ 
+   SET_BIT (visited, bb->index);
+ 
+   FOR_EACH_EDGE (e, ei, bb->succs)
+     {
+       basic_block bs = e->dest;
+       
+       if (info[bb->index].computing != no_mode) 
+ 	add_mode_prev_set (j, compute_edge_index (e),
+ 			   info[bb->index].computing);
+     
+       if (bs->index >= 0 && !TEST_BIT (visited, bs->index))
+ 	set_edge_modes_internal (bs, visited, info, j, no_mode);
+     }
+ }
+ 
+ 
+ static void
+ set_edge_modes (struct bb_info *info, int j, int no_mode)
+ {
+   sbitmap visited = sbitmap_alloc (last_basic_block);
+   sbitmap_zero (visited);
+ 
+   set_edge_modes_internal (ENTRY_BLOCK_PTR->next_bb, visited, info, j, no_mode);
+ 
+   sbitmap_free (visited);
+ }
+ 
+ 
  /* Find all insns that need a particular mode setting, and insert the
     necessary mode switches.  Return true if we did work.  */
  
*************** optimize_mode_switching (void)
*** 390,396 ****
    basic_block bb;
    int need_commit = 0;
    sbitmap *kill;
-   struct edge_list *edge_list;
    static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING;
  #define N_ENTITIES ARRAY_SIZE (num_modes)
    int entity_map[N_ENTITIES];
--- 608,613 ----
*************** optimize_mode_switching (void)
*** 400,405 ****
--- 617,623 ----
    int max_num_modes = 0;
    bool emited = false;
    basic_block post_entry ATTRIBUTE_UNUSED, pre_exit ATTRIBUTE_UNUSED;
+   sbitmap *avin, *avout;
  
    clear_bb_flags ();
  
*************** optimize_mode_switching (void)
*** 431,441 ****
--- 649,663 ----
    pre_exit = create_pre_exit (n_entities, entity_map, num_modes);
  #endif
  
+   init_edge_list ();
+ 
    /* Create the bitmap vectors.  */
  
    antic = sbitmap_vector_alloc (last_basic_block, n_entities);
    transp = sbitmap_vector_alloc (last_basic_block, n_entities);
    comp = sbitmap_vector_alloc (last_basic_block, n_entities);
+   avin = sbitmap_vector_alloc (last_basic_block, n_entities);
+   avout = sbitmap_vector_alloc (last_basic_block, n_entities);
  
    sbitmap_vector_ones (transp, last_basic_block);
  
*************** optimize_mode_switching (void)
*** 538,552 ****
--- 760,779 ----
      }
  
    kill = sbitmap_vector_alloc (last_basic_block, n_entities);
+ 
+   init_mode_info (n_entities);
+ 
    for (i = 0; i < max_num_modes; i++)
      {
        int current_mode[N_ENTITIES];
+       struct edge_list *edge_list;
        sbitmap *delete;
        sbitmap *insert;
  
        /* Set the anticipatable and computing arrays.  */
        sbitmap_vector_zero (antic, last_basic_block);
        sbitmap_vector_zero (comp, last_basic_block);
+ 
        for (j = n_entities - 1; j >= 0; j--)
  	{
  	  int m = current_mode[j] = MODE_PRIORITY_TO_MODE (entity_map[j], i);
*************** optimize_mode_switching (void)
*** 567,574 ****
  
        FOR_EACH_BB (bb)
  	sbitmap_not (kill[bb->index], transp[bb->index]);
!       edge_list = pre_edge_lcm (n_entities, transp, comp, antic,
! 				kill, &insert, &delete);
  
        for (j = n_entities - 1; j >= 0; j--)
  	{
--- 794,801 ----
  
        FOR_EACH_BB (bb)
  	sbitmap_not (kill[bb->index], transp[bb->index]);
!       edge_list = pre_edge_lcm_avs (n_entities, transp, comp, antic,
! 				kill, avin, avout, &insert, &delete);
  
        for (j = n_entities - 1; j >= 0; j--)
  	{
*************** optimize_mode_switching (void)
*** 586,622 ****
  	    {
  	      edge eg = INDEX_EDGE (edge_list, e);
  	      int mode;
! 	      basic_block src_bb;
! 	      HARD_REG_SET live_at_edge;
! 	      rtx mode_set;
! 
! 	      eg->aux = 0;
  
! 	      if (! TEST_BIT (insert[e], j))
! 		continue;
  
! 	      eg->aux = (void *)1;
  
  	      mode = current_mode[j];
- 	      src_bb = eg->src;
  
! 	      REG_SET_TO_HARD_REG_SET (live_at_edge,
! 				       src_bb->il.rtl->global_live_at_end);
! 
! 	      start_sequence ();
! 	      EMIT_MODE_SET (entity_map[j], mode, live_at_edge);
! 	      mode_set = get_insns ();
! 	      end_sequence ();
! 
! 	      /* Do not bother to insert empty sequence.  */
! 	      if (mode_set == NULL_RTX)
! 		continue;
  
! 	      /* We should not get an abnormal edge here.  */
! 	      gcc_assert (! (eg->flags & EDGE_ABNORMAL));
  
! 	      need_commit = 1;
! 	      insert_insn_on_edge (mode_set, eg);
  	    }
  
  	  FOR_EACH_BB_REVERSE (bb)
--- 813,841 ----
  	    {
  	      edge eg = INDEX_EDGE (edge_list, e);
  	      int mode;
!  	      basic_block src_bb;
  
! 	      src_bb = eg->src;
  
! 	      eg->aux = (void *)0;
  
  	      mode = current_mode[j];
  
! 	      if (! TEST_BIT (insert[e], j))
! 		{
! 		  /* The mode was already inserted, but a new one is found at
! 		     'avin'. Update the mode_info.  */
! 		  if (eg->src != ENTRY_BLOCK_PTR
! 		      && !(eg->flags & EDGE_ABNORMAL)
! 		      && TEST_BIT (avin[src_bb->index], j))
! 		    add_mode_prev_set(j, e, mode);
! 		  continue;
! 		}
  
! 	      eg->aux = (void *)1;
  
! 	      /* Remember we need to emit this it.  */
! 	      add_mode_set(j, e, mode);
  	    }
  
  	  FOR_EACH_BB_REVERSE (bb)
*************** optimize_mode_switching (void)
*** 639,647 ****
--- 858,874 ----
      {
        int no_mode = num_modes[entity_map[j]];
  
+       /* In case there was no mode inserted. the mode information on the edge
+ 	 might not be complete. 
+ 	 Update mode info on edges and commit pending mode sets.  */
+       set_edge_modes (bb_info[j], j, no_mode);
+       need_commit |= commit_mode_sets (j);
+ 
        FOR_EACH_BB_REVERSE (bb)
  	{
  	  struct seginfo *ptr, *next;
+ 	  int last_mode = known_mode(bb, j);
+ 
  	  for (ptr = bb_info[j][bb->index].seginfo; ptr; ptr = next)
  	    {
  	      next = ptr->next;
*************** optimize_mode_switching (void)
*** 650,659 ****
  		  rtx mode_set;
  
  		  start_sequence ();
! 		  EMIT_MODE_SET (entity_map[j], ptr->mode, ptr->regs_live);
  		  mode_set = get_insns ();
  		  end_sequence ();
  
  		  /* Insert MODE_SET only if it is nonempty.  */
  		  if (mode_set != NULL_RTX)
  		    {
--- 877,888 ----
  		  rtx mode_set;
  
  		  start_sequence ();
! 		  EMIT_MODE_SET (entity_map[j], ptr->mode, last_mode, ptr->regs_live);
  		  mode_set = get_insns ();
  		  end_sequence ();
  
+ 		  last_mode = ptr->mode;
+ 
  		  /* Insert MODE_SET only if it is nonempty.  */
  		  if (mode_set != NULL_RTX)
  		    {
*************** optimize_mode_switching (void)
*** 674,685 ****
--- 903,918 ----
        free (bb_info[j]);
      }
  
+   free_mode_info (n_entities);
+ 
    /* Finished. Free up all the things we've allocated.  */
  
    sbitmap_vector_free (kill);
    sbitmap_vector_free (antic);
    sbitmap_vector_free (transp);
    sbitmap_vector_free (comp);
+   sbitmap_vector_free (avout);
+   sbitmap_vector_free (avin);
  
    if (need_commit)
      commit_edge_insertions ();

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]