public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PING][PATCH] Extend mode-switching to support toggle (1/2)
@ 2014-04-28  8:12 Christian Bruel
  2014-05-12  8:44 ` [PING*2][PATCH] " Christian Bruel
  0 siblings, 1 reply; 21+ messages in thread
From: Christian Bruel @ 2014-04-28  8:12 UTC (permalink / raw)
  To: gcc-patches

Hello,

I'd like to ping the following patches

[Hookize mode-switching]
http://gcc.gnu.org/ml/gcc-patches/2014-04/msg01003.html

[Add new hooks to support toggle and SH4A fpchg instruction]
http://gcc.gnu.org/ml/gcc-patches/2014-04/msg01005.html

Many thanks




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PING*2][PATCH] Extend mode-switching to support toggle (1/2)
  2014-04-28  8:12 [PING][PATCH] Extend mode-switching to support toggle (1/2) Christian Bruel
@ 2014-05-12  8:44 ` Christian Bruel
  2014-05-12  9:06   ` Christian Bruel
  0 siblings, 1 reply; 21+ messages in thread
From: Christian Bruel @ 2014-05-12  8:44 UTC (permalink / raw)
  To: gcc-patches

Hello,

I'd still wish to ping for the following set of patches. Those changes
does not impact other targets than SH4 but, as suggested by Joern, I
have hooked the macros and moved the SH4A specific support to the target
parts (so a different target can eventually implement other models than
dual mode).

Patch2 only does very little restructuring  but if is not interesting
enough for all targets, patch 1 should not be that intrusive.

For RTL middle end and (X86, SH, Epiphany) target reviewers,

Many thanks,

Christian

On 04/28/2014 10:08 AM, Christian Bruel wrote:
> Hello,
>
> I'd like to ping the following patches
>
> [Hookize mode-switching]
> http://gcc.gnu.org/ml/gcc-patches/2014-04/msg01003.html
>
> [Add new hooks to support toggle and SH4A fpchg instruction]
> http://gcc.gnu.org/ml/gcc-patches/2014-04/msg01005.html
>
> Many thanks
>
>
>
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PING*2][PATCH] Extend mode-switching to support toggle (1/2)
  2014-05-12  8:44 ` [PING*2][PATCH] " Christian Bruel
@ 2014-05-12  9:06   ` Christian Bruel
  2014-05-12 10:32     ` Kaz Kojima
  2014-05-12 11:11     ` Joern Rennecke
  0 siblings, 2 replies; 21+ messages in thread
From: Christian Bruel @ 2014-05-12  9:06 UTC (permalink / raw)
  To: gcc-patches; +Cc: law, Joern Rennecke, Kaz Kojima

Just saw the Jeff's approval for the RTL part. Sorry for the crossed answers

remains the target maintainers.  Joern, Kaz ?

Many thanks.

Christian

On 05/12/2014 10:44 AM, Christian Bruel wrote:
> Hello,
>
> I'd still wish to ping for the following set of patches. Those changes
> does not impact other targets than SH4 but, as suggested by Joern, I
> have hooked the macros and moved the SH4A specific support to the target
> parts (so a different target can eventually implement other models than
> dual mode).
>
> Patch2 only does very little restructuring  but if is not interesting
> enough for all targets, patch 1 should not be that intrusive.
>
> For RTL middle end and (X86, SH, Epiphany) target reviewers,
>
> Many thanks,
>
> Christian
>
> On 04/28/2014 10:08 AM, Christian Bruel wrote:
>> Hello,
>>
>> I'd like to ping the following patches
>>
>> [Hookize mode-switching]
>> http://gcc.gnu.org/ml/gcc-patches/2014-04/msg01003.html
>>
>> [Add new hooks to support toggle and SH4A fpchg instruction]
>> http://gcc.gnu.org/ml/gcc-patches/2014-04/msg01005.html
>>
>> Many thanks
>>
>>
>>
>>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PING*2][PATCH] Extend mode-switching to support toggle (1/2)
  2014-05-12  9:06   ` Christian Bruel
@ 2014-05-12 10:32     ` Kaz Kojima
  2014-05-12 22:35       ` Oleg Endo
  2014-05-12 11:11     ` Joern Rennecke
  1 sibling, 1 reply; 21+ messages in thread
From: Kaz Kojima @ 2014-05-12 10:32 UTC (permalink / raw)
  To: christian.bruel; +Cc: gcc-patches, law, joern.rennecke, oleg.endo

[I'd like to add Oleg to CC list.]

Christian Bruel <christian.bruel@st.com> wrote:
> Just saw the Jeff's approval for the RTL part. Sorry for the crossed answers
> 
> remains the target maintainers.  Joern, Kaz ?

SH specific part looks OK to me.  Oleg, could you comment on
the patch?

Regards,
	kaz

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PING*2][PATCH] Extend mode-switching to support toggle (1/2)
  2014-05-12  9:06   ` Christian Bruel
  2014-05-12 10:32     ` Kaz Kojima
@ 2014-05-12 11:11     ` Joern Rennecke
  2014-05-12 12:16       ` Christian Bruel
  1 sibling, 1 reply; 21+ messages in thread
From: Joern Rennecke @ 2014-05-12 11:11 UTC (permalink / raw)
  To: Christian Bruel; +Cc: GCC Patches, Jeff Law, Kaz Kojima

On 12 May 2014 10:06, Christian Bruel <christian.bruel@st.com> wrote:
> Just saw the Jeff's approval for the RTL part. Sorry for the crossed answers
>
> remains the target maintainers.  Joern, Kaz ?
>
> Many thanks.
>
> Christian
>
> On 05/12/2014 10:44 AM, Christian Bruel wrote:
>> Hello,
>>
>> I'd still wish to ping for the following set of patches. Those changes
>> does not impact other targets than SH4 but, as suggested by Joern, I
>> have hooked the macros and moved the SH4A specific support to the target
>> parts (so a different target can eventually implement other models than
>> dual mode).
>>
>> Patch2 only does very little restructuring  but if is not interesting
>> enough for all targets, patch 1 should not be that intrusive.
>>
>> For RTL middle end and (X86, SH, Epiphany) target reviewers,
>>
>> Many thanks,
>>
>> Christian
>>
>> On 04/28/2014 10:08 AM, Christian Bruel wrote:
>>> Hello,
>>>
>>> I'd like to ping the following patches
>>>
>>> [Hookize mode-switching]
>>> http://gcc.gnu.org/ml/gcc-patches/2014-04/msg01003.html
>>>
>>> [Add new hooks to support toggle and SH4A fpchg instruction]
>>> http://gcc.gnu.org/ml/gcc-patches/2014-04/msg01005.html

Sorry, I only saw the first part and thought I' d need to wait till I
see the second part - and I somehow missed that.

I think the previous known mode should be passed to the
TARGET_MODE_EMIT hook - no need to have extra hooks
for toggling, and, as I mentioned earlier, fixating on the toggle is
actually an SH artifact - other ports have multi-way
modes settings that can benefit from knowing the previous mode.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PING*2][PATCH] Extend mode-switching to support toggle (1/2)
  2014-05-12 11:11     ` Joern Rennecke
@ 2014-05-12 12:16       ` Christian Bruel
  2014-05-12 12:51         ` Joern Rennecke
  2014-05-26 15:32         ` Christian Bruel
  0 siblings, 2 replies; 21+ messages in thread
From: Christian Bruel @ 2014-05-12 12:16 UTC (permalink / raw)
  To: Joern Rennecke; +Cc: GCC Patches, Jeff Law, Kaz Kojima, Oleg Endo

On 04/28/2014 10:08 AM, Christian Bruel wrote:
>>>> Hello,
>>>>
>>>> I'd like to ping the following patches
>>>>
>>>> [Hookize mode-switching]
>>>> http://gcc.gnu.org/ml/gcc-patches/2014-04/msg01003.html
>>>>
>>>> [Add new hooks to support toggle and SH4A fpchg instruction]
>>>> http://gcc.gnu.org/ml/gcc-patches/2014-04/msg01005.html
> Sorry, I only saw the first part and thought I' d need to wait till I
> see the second part - and I somehow missed that.
>
> I think the previous known mode should be passed to the
> TARGET_MODE_EMIT hook - no need to have extra hooks
> for toggling, and, as I mentioned earlier, fixating on the toggle is
> actually an SH artifact - other ports have multi-way
> modes settings that can benefit from knowing the previous mode.

OK I'll change the bool toggle parameter by the previous mode in
TARGET_MODE_EMIT and remove the bool XOR hooks in the SH description.
Just for my curiosity, which other targets have multi-way toggling
support ?

I'll commit the first patch as approved and re post the second one.

Many thanks,

Christian


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PING*2][PATCH] Extend mode-switching to support toggle (1/2)
  2014-05-12 12:16       ` Christian Bruel
@ 2014-05-12 12:51         ` Joern Rennecke
  2014-05-12 13:02           ` Joern Rennecke
  2014-05-12 22:39           ` Oleg Endo
  2014-05-26 15:32         ` Christian Bruel
  1 sibling, 2 replies; 21+ messages in thread
From: Joern Rennecke @ 2014-05-12 12:51 UTC (permalink / raw)
  To: Christian Bruel; +Cc: GCC Patches, Jeff Law, Kaz Kojima, Oleg Endo

On 12 May 2014 13:16, Christian Bruel <christian.bruel@st.com> wrote:

> Just for my curiosity, which other targets have multi-way toggling
> support ?

The epiphany has, sort of: you read a control register, AND and/or OR
some mask(s) to the value,
and write it back.
If we knew the previous mode, we might elide and AND or an OR.

I think this is actually quite a common issue.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PING*2][PATCH] Extend mode-switching to support toggle (1/2)
  2014-05-12 12:51         ` Joern Rennecke
@ 2014-05-12 13:02           ` Joern Rennecke
  2014-05-12 22:39           ` Oleg Endo
  1 sibling, 0 replies; 21+ messages in thread
From: Joern Rennecke @ 2014-05-12 13:02 UTC (permalink / raw)
  To: Christian Bruel; +Cc: GCC Patches, Jeff Law, Kaz Kojima, Oleg Endo

On 12 May 2014 13:51, Joern Rennecke <joern.rennecke@embecosm.com> wrote:
> On 12 May 2014 13:16, Christian Bruel <christian.bruel@st.com> wrote:
>
>> Just for my curiosity, which other targets have multi-way toggling
>> support ?
>
> The epiphany has, sort of: you read a control register, AND and/or OR
> some mask(s) to the value,
> and write it back.
> If we knew the previous mode, we might elide and AND or an OR.
>
> I think this is actually quite a common issue.

P.S.: In some cases, multiple modes input could still be handled if we
knew that certain other modes
don't appear in the input, so a more powerful interface than providing
the previous mode - if known,
is to provide a set of potential predecessor modes.
The case where we don't know anything then obviously is represented as
the full base set.
In the mode switching infrastructure, you can just calculate the union
of the incoming (potential) mode(s) from each incoming edge.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PING*2][PATCH] Extend mode-switching to support toggle (1/2)
  2014-05-12 10:32     ` Kaz Kojima
@ 2014-05-12 22:35       ` Oleg Endo
  0 siblings, 0 replies; 21+ messages in thread
From: Oleg Endo @ 2014-05-12 22:35 UTC (permalink / raw)
  To: Kaz Kojima; +Cc: christian.bruel, gcc-patches, law, joern.rennecke

On Mon, 2014-05-12 at 19:32 +0900, Kaz Kojima wrote:
> [I'd like to add Oleg to CC list.]
> 
> Christian Bruel <christian.bruel@st.com> wrote:
> > Just saw the Jeff's approval for the RTL part. Sorry for the crossed answers
> > 
> > remains the target maintainers.  Joern, Kaz ?
> 
> SH specific part looks OK to me.  Oleg, could you comment on
> the patch?

Looks OK to me with the 'previous mode vs. toggle' change mentioned by
Jörn here http://gcc.gnu.org/ml/gcc-patches/2014-05/msg00754.html

Except one naming thing (please rename, also the existing ones):
sh4_mode_exit -> sh_mode_exit
sh4_toggle_init -> sh_mode_toggle_init
sh4_toggle_destroy -> sh_mode_toggle_destroy
sh4_toggle_set -> sh_mode_toggle_set
sh4_toggle_test -> sh_mode_toggle_test

Other SH variants also have modes.  E.g. SH2A FPU mode switching is also
done through the sh4_* functions, which is a bit confusing when reading.


A few cosmetic nits:

sh.c:
+static sbitmap *mode_in_flip;  /* flip in mode status for each basic blocks.  */
+static sbitmap *mode_out_flip; /* flip out mode status for each basic blocks.  */
                                                                            ^
'basic block'


mode-switching.c:
+			if (mode != num_modes[e] &&
+			    mode != targetm.mode_switching.exit (e))

The '&&' should go to the beginning of the 2nd line, AFAIK.

+  gcc_assert ((targetm.mode_switching.entry && targetm.mode_switching.exit) ||
+	      (!targetm.mode_switching.entry && !targetm.mode_switching.exit));

Likewise.


tm.texi:
+@deftypefn {Target Hook} void TARGET_MODE_TOGGLE_SET (sbitmap *@var{avin}, sbitmap *@var{avout})
+Hook called by the mode switching pass to record the modes needed for each entities in entry and exit of each basic block.
+@end deftypefn

'for each entity'

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PING*2][PATCH] Extend mode-switching to support toggle (1/2)
  2014-05-12 12:51         ` Joern Rennecke
  2014-05-12 13:02           ` Joern Rennecke
@ 2014-05-12 22:39           ` Oleg Endo
  2014-05-13  8:11             ` Joern Rennecke
  1 sibling, 1 reply; 21+ messages in thread
From: Oleg Endo @ 2014-05-12 22:39 UTC (permalink / raw)
  To: Joern Rennecke; +Cc: Christian Bruel, GCC Patches, Jeff Law, Kaz Kojima

On Mon, 2014-05-12 at 13:51 +0100, Joern Rennecke wrote:
> On 12 May 2014 13:16, Christian Bruel <christian.bruel@st.com> wrote:
> 
> > Just for my curiosity, which other targets have multi-way toggling
> > support ?
> 
> The epiphany has, sort of: you read a control register, AND and/or OR
> some mask(s) to the value,
> and write it back.
> If we knew the previous mode, we might elide and AND or an OR.
> 
> I think this is actually quite a common issue.

This is the same as changing/setting the FP modes (PR, SZ) on SH while
preserving the other FPSCR bits, or did I miss something?

Cheers,
Oleg


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PING*2][PATCH] Extend mode-switching to support toggle (1/2)
  2014-05-12 22:39           ` Oleg Endo
@ 2014-05-13  8:11             ` Joern Rennecke
  2014-05-13 21:41               ` Oleg Endo
  0 siblings, 1 reply; 21+ messages in thread
From: Joern Rennecke @ 2014-05-13  8:11 UTC (permalink / raw)
  To: Oleg Endo; +Cc: Christian Bruel, GCC Patches, Jeff Law, Kaz Kojima

On 12 May 2014 23:39, Oleg Endo <oleg.endo@t-online.de> wrote:

> This is the same as changing/setting the FP modes (PR, SZ) on SH while
> preserving the other FPSCR bits, or did I miss something?

It's more like if you have to control multiple bits at once to get a
specific mode.
Say you have to turn SZ off and PR on.  You you knew that only one bit needs
changing, you can do with one less arithmetic operation.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PING*2][PATCH] Extend mode-switching to support toggle (1/2)
  2014-05-13  8:11             ` Joern Rennecke
@ 2014-05-13 21:41               ` Oleg Endo
  2014-06-10 14:03                 ` Joern Rennecke
  0 siblings, 1 reply; 21+ messages in thread
From: Oleg Endo @ 2014-05-13 21:41 UTC (permalink / raw)
  To: Joern Rennecke; +Cc: Christian Bruel, GCC Patches, Jeff Law, Kaz Kojima

On Tue, 2014-05-13 at 09:10 +0100, Joern Rennecke wrote:
> On 12 May 2014 23:39, Oleg Endo <oleg.endo@t-online.de> wrote:
> 
> > This is the same as changing/setting the FP modes (PR, SZ) on SH while
> > preserving the other FPSCR bits, or did I miss something?
> 
> It's more like if you have to control multiple bits at once to get a
> specific mode.
> Say you have to turn SZ off and PR on.  You you knew that only one bit needs
> changing, you can do with one less arithmetic operation.

Right.  I was thinking to add FPSCR.SZ mode switching to SH, in order to
do float vector moves.  For that SZ and PR need to be switched both at
the same time (only SH4A has both, fpchg and fschg).  So basically I'd
add another mode entity, which would emit SZ mode changes in addition to
the PR mode changes.  But then adjacent FPSCR-changing insns could be
combined ... any idea/suggestion how to accomplish that?

Cheers,
Oleg

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PING*2][PATCH] Extend mode-switching to support toggle (1/2)
  2014-05-12 12:16       ` Christian Bruel
  2014-05-12 12:51         ` Joern Rennecke
@ 2014-05-26 15:32         ` Christian Bruel
  2014-06-02 12:34           ` Christian Bruel
  1 sibling, 1 reply; 21+ messages in thread
From: Christian Bruel @ 2014-05-26 15:32 UTC (permalink / raw)
  To: gcc-patches, Jeff Law, Kaz Kojima, Oleg Endo, Joern Rennecke

[-- Attachment #1: Type: text/plain, Size: 2309 bytes --]


> On 04/28/2014 10:08 AM, Christian Bruel wrote:
>>>>> Hello,
>>>>>
>>>>> I'd like to ping the following patches
>>>>>
>>>>> [Hookize mode-switching]
>>>>> http://gcc.gnu.org/ml/gcc-patches/2014-04/msg01003.html
>>>>>
>>>>> [Add new hooks to support toggle and SH4A fpchg instruction]
>>>>> http://gcc.gnu.org/ml/gcc-patches/2014-04/msg01005.html
>> Sorry, I only saw the first part and thought I' d need to wait till I
>> see the second part - and I somehow missed that.
>>
>> I think the previous known mode should be passed to the
>> TARGET_MODE_EMIT hook - no need to have extra hooks
>> for toggling, and, as I mentioned earlier, fixating on the toggle is
>> actually an SH artifact - other ports have multi-way
>> modes settings that can benefit from knowing the previous mode.
> OK I'll change the bool toggle parameter by the previous mode in
> TARGET_MODE_EMIT and remove the bool XOR hooks in the SH description.
>
Hello,

This is the interface for targets that could use the previous mode for
switching. TARGET_MODE_EMIT now takes a new prev_mode parameter. If the
previous mode cannot be determined, MODE_NONE (value depends on  the
entity) is used.

The implementation is less trivial than just supporting a boolean toggle
bit, as the previous modes information have to be carried along the
edges. For this I recycle the auxiliary edge field that is made
unnecessary by the removal of make_pred_opaque and a change in the
implementation to call LCM for every modes from every identity
simultaneously. This idea was suggested by Joern in PR29349.  Another
speed improvement is that we process the modes to no_mode instead of
max_num_modes for each entity.
Thanks to all this, the only additional data to support prev_mode is
that for each BB, the avin/avout lcm computation are cached inside the
bb_info mode_in/mode_out fields,  the xor toggle bit handling  could
have been removed.

bootstrapped/regtested for x86 and sh4, sh4a, sh4a-single,
epiphany build is OK. testsuite not ran.

Joern, is this new target macro interface OK with you ? Jeff, (or other
RTL maintainer) since this is a new implementation for
optimize_mode_switching I suppose your previous approval doesn't held
anymore... is this new one OK for trunk as well ?
No change for x86/sh4/2a interfaces.

Many thanks

Christian



[-- Attachment #2: toggle.patch --]
[-- Type: text/x-patch, Size: 30668 bytes --]

2014-05-23  Christian Bruel  <christian.bruel@st.com>

	* mode-switching.c (struct bb_info): Add mode_out, mode_in caches.
	(make_preds_opaque): Delete function.
	(clear_mode_bit, mode_bit_p, set_mode_bit): New macros.
	(add_mode_set, get_mode_set, alloc_mode_aux, free_modes_edges): New functions.
	(commit_mode_sets): New function.
	(optimize_mode_switching): Handle current_mode to mode_switching_emit.
	Process all modes at once. 
	* basic-block.h (pre_edge_lcm_avs): Declare.
	* lcm.c (pre_edge_lcm_avs): Renamed from pre_edge_lcm.
	Call clear_aux_for_edges. Fix comments.
	(pre_edge_lcm): New wrapper function to call pre_edge_lcm_avs.
	(pre_edge_rev_lcm): Idem.
	* config/epiphany/epiphany.c (emit_set_fp_mode): Add prev_mode parameter.
	* config/epiphany/epiphany-protos.h (emit_set_fp_mode): Idem.
	* config/epiphany/resolve-sw-modes.c (pass_resolve_sw_modes::execute): Idem.
	* config/i386/i386.c (x96_emit_mode_set): Idem.
	* config/sh/sh.c (sh_emit_mode_set): Likewise. Handle PR toggle.
	* config/sh/sh.md (toggle_pr): 	Defined if TARGET_FPU_SINGLE.
	(fpscr_toggle) Disallow from delay slot.
	* target.def (emit_mode_set): Add prev_mode parameter.
	* doc/tm.texi: Regenerate.

2014-05-19  Christian Bruel  <christian.bruel@st.com>

	* gcc.target/sh/fpchg.c: New test.

Index: gcc/basic-block.h
===================================================================
--- gcc/basic-block.h	(revision 210845)
+++ gcc/basic-block.h	(working copy)
@@ -711,6 +711,9 @@ extern void bitmap_union_of_preds (sbitmap, sbitma
 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 **,
Index: gcc/config/epiphany/epiphany-protos.h
===================================================================
--- gcc/config/epiphany/epiphany-protos.h	(revision 210845)
+++ gcc/config/epiphany/epiphany-protos.h	(working copy)
@@ -40,7 +40,8 @@ extern int epiphany_initial_elimination_offset (in
 extern void epiphany_init_expanders (void);
 extern int hard_regno_mode_ok (int regno, enum machine_mode mode);
 #ifdef HARD_CONST
-extern void emit_set_fp_mode (int entity, int mode, HARD_REG_SET regs_live);
+extern void emit_set_fp_mode (int entity, int mode, int prev_mode,
+			      HARD_REG_SET regs_live);
 #endif
 extern void epiphany_insert_mode_switch_use (rtx insn, int, int);
 extern void epiphany_expand_set_fp_mode (rtx *operands);
Index: gcc/config/epiphany/epiphany.c
===================================================================
--- gcc/config/epiphany/epiphany.c	(revision 210845)
+++ gcc/config/epiphany/epiphany.c	(working copy)
@@ -2542,7 +2542,8 @@ epiphany_mode_exit (int entity)
 }
 
 void
-emit_set_fp_mode (int entity, int mode, HARD_REG_SET regs_live ATTRIBUTE_UNUSED)
+emit_set_fp_mode (int entity, int mode, int prev_mode ATTRIBUTE_UNUSED,
+		  HARD_REG_SET regs_live ATTRIBUTE_UNUSED)
 {
   rtx save_cc, cc_reg, mask, src, src2;
   enum attr_fp_mode fp_mode;
Index: gcc/config/epiphany/resolve-sw-modes.c
===================================================================
--- gcc/config/epiphany/resolve-sw-modes.c	(revision 210845)
+++ gcc/config/epiphany/resolve-sw-modes.c	(working copy)
@@ -170,7 +170,7 @@ pass_resolve_sw_modes::execute (function *fun)
 	    }
 	  start_sequence ();
 	  emit_set_fp_mode (EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN,
-			    jilted_mode, NULL);
+			    jilted_mode, FP_MODE_NONE, NULL);
 	  seq = get_insns ();
 	  end_sequence ();
 	  need_commit = true;
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c	(revision 210845)
+++ gcc/config/i386/i386.c	(working copy)
@@ -16440,7 +16440,8 @@ ix86_avx_emit_vzeroupper (HARD_REG_SET regs_live)
    are to be inserted.  */
 
 static void
-ix86_emit_mode_set (int entity, int mode, HARD_REG_SET regs_live)
+ix86_emit_mode_set (int entity, int mode, int prev_mode ATTRIBUTE_UNUSED,
+		    HARD_REG_SET regs_live)
 {
   switch (entity)
     {
Index: gcc/config/sh/sh.c
===================================================================
--- gcc/config/sh/sh.c	(revision 210845)
+++ gcc/config/sh/sh.c	(working copy)
@@ -202,7 +202,7 @@ static void push_regs (HARD_REG_SET *, int);
 static int calc_live_regs (HARD_REG_SET *);
 static HOST_WIDE_INT rounded_frame_size (int);
 static bool sh_frame_pointer_required (void);
-static void sh_emit_mode_set (int, int, HARD_REG_SET);
+static void sh_emit_mode_set (int, int, int, HARD_REG_SET);
 static int sh_mode_needed (int, rtx);
 static int sh_mode_after (int, int, rtx);
 static int sh_mode_entry (int);
@@ -13582,9 +13582,17 @@ sh_try_omit_signzero_extend (rtx extended_op, rtx
 
 static void
 sh_emit_mode_set (int entity ATTRIBUTE_UNUSED, int mode,
-		  HARD_REG_SET regs_live)
+		  int prev_mode, HARD_REG_SET regs_live)
 {
-  fpscr_set_from_mem (mode, regs_live);
+  if ((TARGET_SH4A_FP || TARGET_SH4_300)
+      && prev_mode != FP_MODE_NONE && prev_mode != mode)
+    {
+      emit_insn (gen_toggle_pr ());
+      if (TARGET_FMOVD)
+	emit_insn (gen_toggle_sz ());
+    }
+  else
+    fpscr_set_from_mem (mode, regs_live);
 }
 
 static int
Index: gcc/config/sh/sh.md
===================================================================
--- gcc/config/sh/sh.md	(revision 210845)
+++ gcc/config/sh/sh.md	(working copy)
@@ -504,6 +504,7 @@
 (define_attr "in_delay_slot" "yes,no"
   (cond [(eq_attr "type" "cbranch") (const_string "no")
 	 (eq_attr "type" "pcload,pcload_si") (const_string "no")
+	 (eq_attr "type" "fpscr_toggle") (const_string "no")
 	 (eq_attr "needs_delay_slot" "yes") (const_string "no")
 	 (eq_attr "length" "2") (const_string "yes")
 	 ] (const_string "no")))
@@ -12239,15 +12240,12 @@ label:
   "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).
+;; Toggle FPU precision PR mode.
+
 (define_insn "toggle_pr"
   [(set (reg:PSI FPSCR_REG)
 	(xor:PSI (reg:PSI FPSCR_REG) (const_int 524288)))]
-  "TARGET_SH4A_FP && ! TARGET_FPU_SINGLE"
+  "TARGET_SH4A_FP"
   "fpchg"
   [(set_attr "type" "fpscr_toggle")])
 
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi	(revision 210845)
+++ gcc/doc/tm.texi	(working copy)
@@ -9737,12 +9737,12 @@ represented as numbers 0 @dots{} N @minus{} 1.  N
 switch is needed / supplied.
 @end defmac
 
-@deftypefn {Target Hook} void TARGET_MODE_EMIT (int @var{entity}, int @var{mode}, HARD_REG_SET @var{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. Sets of a lower numbered entity will be emitted before sets of a higher numbered entity to a mode of the same or lower priority.
+@deftypefn {Target Hook} void TARGET_MODE_EMIT (int @var{entity}, int @var{mode}, int @var{prev_mode}, HARD_REG_SET @var{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{prev_moxde} indicates the mode to switch from. Sets of a lower numbered entity will be emitted before sets of a higher numbered entity to a mode of the same or lower priority.
 @end deftypefn
 
 @deftypefn {Target Hook} int TARGET_MODE_NEEDED (int @var{entity}, rtx @var{insn})
-@var{entity} is an integer specifying a mode-switched entity. If @code{OPTIMIZE_MODE_SWITCHING} is defined, you must define this macro to return an integer value not larger than the corresponding element in @code{NUM_MODES_FOR_MODE_SWITCHING}, to denote the mode that @var{entity} must be switched into prior to the execution of @var{insn}.
+@var{entity} is an integer specifying a mode-switched entity.  If @code{OPTIMIZE_MODE_SWITCHING} is defined, you must define this macro to return an integer value not larger than the corresponding element in @code{NUM_MODES_FOR_MODE_SWITCHING}, to denote the mode that @var{entity} must be switched into prior to the execution of @var{insn}.
 @end deftypefn
 
 @deftypefn {Target Hook} int TARGET_MODE_AFTER (int @var{entity}, int @var{mode}, rtx @var{insn})
Index: gcc/lcm.c
===================================================================
--- gcc/lcm.c	(revision 210845)
+++ gcc/lcm.c	(working copy)
@@ -377,17 +377,17 @@ compute_insert_delete (struct edge_list *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
+/* Given local properties TRANSP, ANTLOC, AVLOC, KILL return the insert and
+   delete vectors for edge based LCM  and return the AVIN, AVOUT bitmap.
    map the insert vector to what edge an expression should be inserted on.  */
 
 struct edge_list *
-pre_edge_lcm (int n_exprs, sbitmap *transp,
+pre_edge_lcm_avs (int n_exprs, sbitmap *transp,
 	      sbitmap *avloc, sbitmap *antloc, sbitmap *kill,
+	      sbitmap *avin, sbitmap *avout,
 	      sbitmap **insert, sbitmap **del)
 {
   sbitmap *antin, *antout, *earliest;
-  sbitmap *avin, *avout;
   sbitmap *later, *laterin;
   struct edge_list *edge_list;
   int num_edges;
@@ -413,10 +413,7 @@ struct edge_list *
 #endif
 
   /* Compute global availability.  */
-  avin = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_exprs);
-  avout = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_exprs);
   compute_available (avloc, kill, avout, avin);
-  sbitmap_vector_free (avin);
 
   /* Compute global anticipatability.  */
   antin = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_exprs);
@@ -444,7 +441,6 @@ struct edge_list *
 
   sbitmap_vector_free (antout);
   sbitmap_vector_free (antin);
-  sbitmap_vector_free (avout);
 
   later = sbitmap_vector_alloc (num_edges, n_exprs);
 
@@ -485,6 +481,28 @@ struct edge_list *
   return edge_list;
 }
 
+/* Wrapper to allocate avin/avout and call pre_edge_lcm_avs.  */
+
+struct edge_list *
+pre_edge_lcm (int n_exprs, sbitmap *transp,
+	      sbitmap *avloc, sbitmap *antloc, sbitmap *kill,
+	      sbitmap **insert, sbitmap **del)
+{
+  struct edge_list *edge_list;
+  sbitmap *avin, *avout;
+
+  avin = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_exprs);
+  avout = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_exprs);
+
+  edge_list = pre_edge_lcm_avs (n_exprs, transp, avloc, antloc, kill,
+				 avin, avout, insert, del);
+
+  sbitmap_vector_free (avout);
+  sbitmap_vector_free (avin);
+
+  return edge_list;
+}
+
 /* Compute the AVIN and AVOUT vectors from the AVLOC and KILL vectors.
    Return the number of passes we performed to iterate to a solution.  */
 
Index: gcc/mode-switching.c
===================================================================
--- gcc/mode-switching.c	(revision 210845)
+++ gcc/mode-switching.c	(working copy)
@@ -80,23 +80,119 @@ struct bb_info
 {
   struct seginfo *seginfo;
   int computing;
+  int mode_out;
+  int mode_in;
 };
 
-/* These bitmaps are used for the LCM algorithm.  */
-
-static sbitmap *antic;
-static sbitmap *transp;
-static sbitmap *comp;
-
 static struct seginfo * new_seginfo (int, rtx, int, HARD_REG_SET);
 static void add_seginfo (struct bb_info *, struct seginfo *);
 static void reg_dies (rtx, HARD_REG_SET *);
 static void reg_becomes_live (rtx, const_rtx, void *);
-static void make_preds_opaque (basic_block, int);
-\f
 
-/* This function will allocate a new BBINFO structure, initialized
-   with the MODE, INSN, and basic block BB parameters.
+/* Clear ode I from entity J in bitmap B.  */
+#define clear_mode_bit(b, j, i) \
+       bitmap_clear_bit (b, (j * max_num_modes) + i)
+
+/* Test mode I from entity J in bitmap B.  */
+#define mode_bit_p(b, j, i) \
+       bitmap_bit_p (b, (j * max_num_modes) + i)
+
+/* Set mode I from entity J in bitmal B.  */
+#define set_mode_bit(b, j, i) \
+       bitmap_set_bit (b, (j * max_num_modes) + i)
+
+/* Record the MODE associated with edge EG for entity E.  */
+
+static void
+add_mode_set (int e, edge eg, int mode)
+{
+  ((int*)eg->aux)[e] = mode;
+}
+
+/* Return the mode needed on edge EG for entity E.  */
+
+static int
+get_mode_set (int e, edge eg)
+{
+  return eg->aux != NULL ? ((int*)eg->aux)[e] : -1;
+}
+
+/* Allocate the modes area on edge EG. Initialized with -1.  */
+
+static void
+alloc_mode_aux (edge eg, int n_entities, int *entity_map)
+{
+  eg->aux = (int *)xmalloc (sizeof (int) *  n_entities);
+
+  for (int j = n_entities - 1; j >= 0; j--)
+    add_mode_set (entity_map[j], eg,  -1);
+}
+
+static void
+free_modes_edges (struct edge_list *edge_list)
+{
+  for (int ed = NUM_EDGES (edge_list) - 1; ed >= 0; ed--)
+    {
+      edge eg = INDEX_EDGE (edge_list, ed);
+
+      if (eg->aux)
+	{
+	  free (eg->aux);
+	  eg->aux = NULL;
+	}
+    }
+
+  free_edge_list (edge_list);
+}
+
+/* Emit modes segments from EDGE_LIST associated with entity E.
+   INFO gives mode availability for each mode.  */
+
+static bool
+commit_mode_sets (struct edge_list *edge_list, int e, struct bb_info *info)
+{
+  bool need_commit = false;
+
+  for (int ed = NUM_EDGES (edge_list) - 1; ed >= 0; ed--)
+    {
+      edge eg = INDEX_EDGE (edge_list, ed);
+      int mode;
+
+      if ((mode = get_mode_set (e, eg)) != -1)
+	{
+	  HARD_REG_SET live_at_edge;
+	  basic_block src_bb = eg->src;
+	  int cur_mode = info[src_bb->index].mode_out;
+	  rtx mode_set;
+
+	  REG_SET_TO_HARD_REG_SET (live_at_edge, df_get_live_out (src_bb));
+
+	  rtl_profile_for_edge (eg);
+	  start_sequence ();
+
+	  targetm.mode_switching.emit (e, mode, cur_mode, live_at_edge);
+
+	  mode_set = get_insns ();
+	  end_sequence ();
+	  default_rtl_profile ();
+
+	  /* 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 = true;
+	  insert_insn_on_edge (mode_set, eg);
+	}
+    }
+
+  return need_commit;
+}
+
+/* Allocate a new BBINFO structure, initialized with the MODE, INSN,
+   and basic block BB parameters.
    INSN may not be a NOTE_INSN_BASIC_BLOCK, unless it is an empty
    basic block; that allows us later to insert instructions in a FIFO-like
    manner.  */
@@ -137,30 +233,6 @@ add_seginfo (struct bb_info *head, struct seginfo
     }
 }
 
-/* Make all predecessors of basic block B opaque, recursively, till we hit
-   some that are already non-transparent, or an edge where aux is set; that
-   denotes that a mode set is to be done on that edge.
-   J is the bit number in the bitmaps that corresponds to the entity that
-   we are currently handling mode-switching for.  */
-
-static void
-make_preds_opaque (basic_block b, int j)
-{
-  edge e;
-  edge_iterator ei;
-
-  FOR_EACH_EDGE (e, ei, b->preds)
-    {
-      basic_block pb = e->src;
-
-      if (e->aux || ! bitmap_bit_p (transp[pb->index], j))
-	continue;
-
-      bitmap_clear_bit (transp[pb->index], j);
-      make_preds_opaque (pb, j);
-    }
-}
-
 /* Record in LIVE that register REG died.  */
 
 static void
@@ -452,24 +524,26 @@ create_pre_exit (int n_entities, int *entity_map,
 static int
 optimize_mode_switching (void)
 {
-  rtx insn;
   int e;
   basic_block bb;
-  int need_commit = 0;
-  sbitmap *kill;
-  struct edge_list *edge_list;
+  bool need_commit = false;
   static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING;
 #define N_ENTITIES ARRAY_SIZE (num_modes)
   int entity_map[N_ENTITIES];
   struct bb_info *bb_info[N_ENTITIES];
   int i, j;
-  int n_entities;
+  int n_entities = 0;
   int max_num_modes = 0;
   bool emitted ATTRIBUTE_UNUSED = false;
   basic_block post_entry = 0;
   basic_block pre_exit = 0;
+  struct edge_list *edge_list = 0;
 
-  for (e = N_ENTITIES - 1, n_entities = 0; e >= 0; e--)
+  /* These bitmaps are used for the LCM algorithm.  */
+  sbitmap *kill, *del, *insert, *antic, *transp, *comp;
+  sbitmap *avin, *avout;
+
+  for (e = N_ENTITIES - 1; e >= 0; e--)
     if (OPTIMIZE_MODE_SWITCHING (e))
       {
 	int entry_exit_extra = 0;
@@ -491,9 +565,10 @@ optimize_mode_switching (void)
   if (! n_entities)
     return 0;
 
-  /* Make sure if MODE_ENTRY is defined the MODE_EXIT is defined and vice versa.  */
+  /* Make sure if MODE_ENTRY is defined MODE_EXIT is defined.  */
   gcc_assert ((targetm.mode_switching.entry && targetm.mode_switching.exit)
-	      || (!targetm.mode_switching.entry && !targetm.mode_switching.exit));
+	      || (!targetm.mode_switching.entry
+		  && !targetm.mode_switching.exit));
 
   if (targetm.mode_switching.entry && targetm.mode_switching.exit)
     {
@@ -506,18 +581,29 @@ optimize_mode_switching (void)
   df_analyze ();
 
   /* Create the bitmap vectors.  */
+  antic = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
+				n_entities * max_num_modes);
+  transp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
+				 n_entities * max_num_modes);
+  comp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
+			       n_entities * max_num_modes);
+  avin = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
+			       n_entities * max_num_modes);
+  avout = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
+				n_entities * max_num_modes);
+  kill = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
+			       n_entities * max_num_modes);
 
-  antic = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_entities);
-  transp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_entities);
-  comp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_entities);
-
   bitmap_vector_ones (transp, last_basic_block_for_fn (cfun));
+  bitmap_vector_clear (antic, last_basic_block_for_fn (cfun));
+  bitmap_vector_clear (comp, last_basic_block_for_fn (cfun));
 
   for (j = n_entities - 1; j >= 0; j--)
     {
       int e = entity_map[j];
       int no_mode = num_modes[e];
       struct bb_info *info = bb_info[j];
+      rtx insn;
 
       /* Determine what the first use (if any) need for a mode of entity E is.
 	 This will be the mode that is anticipatable for this block.
@@ -529,16 +615,18 @@ optimize_mode_switching (void)
 	  bool any_set_required = false;
 	  HARD_REG_SET live_now;
 
+	  info[bb->index].mode_out = info[bb->index].mode_in = no_mode;
+
 	  REG_SET_TO_HARD_REG_SET (live_now, df_get_live_in (bb));
 
 	  /* Pretend the mode is clobbered across abnormal edges.  */
 	  {
 	    edge_iterator ei;
-	    edge e;
-	    FOR_EACH_EDGE (e, ei, bb->preds)
-	      if (e->flags & EDGE_COMPLEX)
+	    edge eg;
+	    FOR_EACH_EDGE (eg, ei, bb->preds)
+	      if (eg->flags & EDGE_COMPLEX)
 		break;
-	    if (e)
+	    if (eg)
 	      {
 		rtx ins_pos = BB_HEAD (bb);
 		if (LABEL_P (ins_pos))
@@ -548,7 +636,8 @@ optimize_mode_switching (void)
 		  ins_pos = NEXT_INSN (ins_pos);
 		ptr = new_seginfo (no_mode, ins_pos, bb->index, live_now);
 		add_seginfo (info + bb->index, ptr);
-		bitmap_clear_bit (transp[bb->index], j);
+		for (i = 0; i < no_mode; i++)
+		  clear_mode_bit (transp[bb->index], j, i);
 	      }
 	  }
 
@@ -565,11 +654,13 @@ optimize_mode_switching (void)
 		      last_mode = mode;
 		      ptr = new_seginfo (mode, insn, bb->index, live_now);
 		      add_seginfo (info + bb->index, ptr);
-		      bitmap_clear_bit (transp[bb->index], j);
+		      for (i = 0; i < no_mode; i++)
+			clear_mode_bit (transp[bb->index], j, i);
 		    }
 
 		  if (targetm.mode_switching.after)
-		    last_mode = targetm.mode_switching.after (e, last_mode, insn);
+		    last_mode = targetm.mode_switching.after (e, last_mode,
+							      insn);
 
 		  /* Update LIVE_NOW.  */
 		  for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
@@ -593,13 +684,22 @@ optimize_mode_switching (void)
 	      ptr = new_seginfo (no_mode, BB_END (bb), bb->index, live_now);
 	      add_seginfo (info + bb->index, ptr);
 	      if (last_mode != no_mode)
-		bitmap_clear_bit (transp[bb->index], j);
+		for (i = 0; i < no_mode; i++)
+		  clear_mode_bit (transp[bb->index], j, i);
 	    }
 	}
       if (targetm.mode_switching.entry && targetm.mode_switching.exit)
 	{
 	  int mode = targetm.mode_switching.entry (e);
 
+	  info[post_entry->index].mode_out =
+	    info[post_entry->index].mode_in = no_mode;
+	  if (pre_exit)
+	    {
+	      info[pre_exit->index].mode_out =
+		info[pre_exit->index].mode_in = no_mode;
+	    }
+
 	  if (mode != no_mode)
 	    {
 	      bb = post_entry;
@@ -608,7 +708,8 @@ optimize_mode_switching (void)
 		 an extra check in make_preds_opaque.  We also
 		 need this to avoid confusing pre_edge_lcm when
 		 antic is cleared but transp and comp are set.  */
-	      bitmap_clear_bit (transp[bb->index], j);
+	      for (i = 0; i < no_mode; i++)
+		clear_mode_bit (transp[bb->index], j, i);
 
 	      /* Insert a fake computing definition of MODE into entry
 		 blocks which compute no mode. This represents the mode on
@@ -620,115 +721,107 @@ optimize_mode_switching (void)
 		  targetm.mode_switching.exit (e);
 	    }
 	}
-    }
 
-  kill = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_entities);
-  for (i = 0; i < max_num_modes; i++)
-    {
-      int current_mode[N_ENTITIES];
-      sbitmap *del;
-      sbitmap *insert;
-
       /* Set the anticipatable and computing arrays.  */
-      bitmap_vector_clear (antic, last_basic_block_for_fn (cfun));
-      bitmap_vector_clear (comp, last_basic_block_for_fn (cfun));
-      for (j = n_entities - 1; j >= 0; j--)
+      for (i = 0; i < no_mode; i++)
 	{
-	  int m = current_mode[j] =
-	    targetm.mode_switching.priority (entity_map[j], i);
-	  struct bb_info *info = bb_info[j];
+	  int m = targetm.mode_switching.priority (entity_map[j], i);
 
 	  FOR_EACH_BB_FN (bb, cfun)
 	    {
 	      if (info[bb->index].seginfo->mode == m)
-		bitmap_set_bit (antic[bb->index], j);
+		set_mode_bit (antic[bb->index], j, m);
 
 	      if (info[bb->index].computing == m)
-		bitmap_set_bit (comp[bb->index], j);
+		set_mode_bit (comp[bb->index], j, m);
 	    }
 	}
+    }
 
-      /* Calculate the optimal locations for the
-	 placement mode switches to modes with priority I.  */
+  /* Calculate the optimal locations for the
+     placement mode switches to modes with priority I.  */
 
-      FOR_EACH_BB_FN (bb, cfun)
-	bitmap_not (kill[bb->index], transp[bb->index]);
-      edge_list = pre_edge_lcm (n_entities, transp, comp, antic,
-				kill, &insert, &del);
+  FOR_EACH_BB_FN (bb, cfun)
+    bitmap_not (kill[bb->index], transp[bb->index]);
 
-      for (j = n_entities - 1; j >= 0; j--)
-	{
-	  /* Insert all mode sets that have been inserted by lcm.  */
-	  int no_mode = num_modes[entity_map[j]];
+  edge_list = pre_edge_lcm_avs (n_entities * max_num_modes, transp, comp, antic,
+				kill, avin, avout, &insert, &del);
 
-	  /* Wherever we have moved a mode setting upwards in the flow graph,
-	     the blocks between the new setting site and the now redundant
-	     computation ceases to be transparent for any lower-priority
-	     mode of the same entity.  First set the aux field of each
-	     insertion site edge non-transparent, then propagate the new
-	     non-transparency from the redundant computation upwards till
-	     we hit an insertion site or an already non-transparent block.  */
-	  for (e = NUM_EDGES (edge_list) - 1; e >= 0; e--)
-	    {
-	      edge eg = INDEX_EDGE (edge_list, e);
-	      int mode;
-	      basic_block src_bb;
-	      HARD_REG_SET live_at_edge;
-	      rtx mode_set;
+  for (j = n_entities - 1; j >= 0; j--)
+    {
+      int no_mode = num_modes[entity_map[j]];
 
-	      eg->aux = 0;
+      /* Insert all mode sets that have been inserted by lcm.  */
 
-	      if (! bitmap_bit_p (insert[e], j))
-		continue;
+      for (int ed = NUM_EDGES (edge_list) - 1; ed >= 0; ed--)
+	{
+	  edge eg = INDEX_EDGE (edge_list, ed);
 
-	      eg->aux = (void *)1;
+	  for (i = 0; i < no_mode; i++)
+	    {
+	      int m = targetm.mode_switching.priority (entity_map[j], i);
 
-	      mode = current_mode[j];
-	      src_bb = eg->src;
-
-	      REG_SET_TO_HARD_REG_SET (live_at_edge, df_get_live_out (src_bb));
-
-	      rtl_profile_for_edge (eg);
-	      start_sequence ();
-	      targetm.mode_switching.emit (entity_map[j], mode, live_at_edge);
-	      mode_set = get_insns ();
-	      end_sequence ();
-	      default_rtl_profile ();
-
-	      /* Do not bother to insert empty sequence.  */
-	      if (mode_set == NULL_RTX)
+	      if (! mode_bit_p (insert[ed], j, m))
 		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);
+	      /* Remember we need to emit it.  */
+	      if (!eg->aux)
+		alloc_mode_aux (eg, n_entities, entity_map);
+	      add_mode_set (entity_map[j], eg, m);
 	    }
+	}
 
-	  FOR_EACH_BB_REVERSE_FN (bb, cfun)
-	    if (bitmap_bit_p (del[bb->index], j))
+      FOR_EACH_BB_FN (bb, cfun)
+	{
+	  struct bb_info *info = bb_info[j];
+	  int last_mode = no_mode;
+
+	  /* intialize mode in availability for bb.  */
+	  for (i = 0; i < no_mode; i++)
+	    if (mode_bit_p (avout[bb->index], j, i))
 	      {
-		make_preds_opaque (bb, j);
-		/* Cancel the 'deleted' mode set.  */
-		bb_info[j][bb->index].seginfo->mode = no_mode;
+		if (last_mode == no_mode)
+		  last_mode = i;
+		if (last_mode != i)
+		  {
+		    last_mode = no_mode;
+		    break;
+		  }
 	      }
+	  info[bb->index].mode_out = last_mode;
+
+	  /* intialize mode out availability for bb.  */
+	  last_mode = no_mode;
+	  for (i = 0; i < no_mode; i++)
+	    if (mode_bit_p (avin[bb->index], j, i))
+	      {
+		if (last_mode == no_mode)
+		  last_mode = i;
+		if (last_mode != i)
+		  {
+		    last_mode = no_mode;
+		    break;
+		  }
+	      }
+	  info[bb->index].mode_in = last_mode;
+
+	  for (i = 0; i < no_mode; i++)
+	    if (mode_bit_p (del[bb->index], j, i))
+	      info[bb->index].seginfo->mode = no_mode;
 	}
 
-      sbitmap_vector_free (del);
-      sbitmap_vector_free (insert);
-      clear_aux_for_edges ();
-      free_edge_list (edge_list);
-    }
+      /* Now output the remaining mode sets in all the segments.  */
 
-  /* Now output the remaining mode sets in all the segments.  */
-  for (j = n_entities - 1; j >= 0; j--)
-    {
-      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.  */
+      need_commit |= commit_mode_sets (edge_list, entity_map[j], bb_info[j]);
 
-      FOR_EACH_BB_REVERSE_FN (bb, cfun)
+      FOR_EACH_BB_FN (bb, cfun)
 	{
 	  struct seginfo *ptr, *next;
+	  int cur_mode = bb_info[j][bb->index].mode_in;
+
 	  for (ptr = bb_info[j][bb->index].seginfo; ptr; ptr = next)
 	    {
 	      next = ptr->next;
@@ -738,12 +831,15 @@ optimize_mode_switching (void)
 
 		  rtl_profile_for_bb (bb);
 		  start_sequence ();
-		  targetm.mode_switching.emit (entity_map[j],
-					       ptr->mode,
-					       ptr->regs_live);
+
+		  targetm.mode_switching.emit (entity_map[j], ptr->mode,
+					       cur_mode, ptr->regs_live);
 		  mode_set = get_insns ();
 		  end_sequence ();
 
+		  /* modes kill each other inside a basic block.  */
+		  cur_mode = ptr->mode;
+
 		  /* Insert MODE_SET only if it is nonempty.  */
 		  if (mode_set != NULL_RTX)
 		    {
@@ -772,11 +868,17 @@ optimize_mode_switching (void)
       free (bb_info[j]);
     }
 
+  free_modes_edges (edge_list);
+
   /* Finished. Free up all the things we've allocated.  */
+  sbitmap_vector_free (del);
+  sbitmap_vector_free (insert);
   sbitmap_vector_free (kill);
   sbitmap_vector_free (antic);
   sbitmap_vector_free (transp);
   sbitmap_vector_free (comp);
+  sbitmap_vector_free (avin);
+  sbitmap_vector_free (avout);
 
   if (need_commit)
     commit_edge_insertions ();
Index: gcc/target.def
===================================================================
--- gcc/target.def	(revision 210845)
+++ gcc/target.def	(working copy)
@@ -5366,12 +5366,12 @@ HOOK_VECTOR (TARGET_TOGGLE_, mode_switching)
 
 DEFHOOK
 (emit,
- "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. Sets of a lower numbered entity will be emitted before sets of a higher numbered entity to a mode of the same or lower priority.",
- void, (int entity, int mode, HARD_REG_SET regs_live), NULL)
+ "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{prev_moxde} indicates the mode to switch from. Sets of a lower numbered entity will be emitted before sets of a higher numbered entity to a mode of the same or lower priority.",
+ void, (int entity, int mode, int prev_mode, HARD_REG_SET regs_live), NULL)
 
 DEFHOOK
 (needed,
- "@var{entity} is an integer specifying a mode-switched entity. If @code{OPTIMIZE_MODE_SWITCHING} is defined, you must define this macro to return an integer value not larger than the corresponding element in @code{NUM_MODES_FOR_MODE_SWITCHING}, to denote the mode that @var{entity} must be switched into prior to the execution of @var{insn}.",
+ "@var{entity} is an integer specifying a mode-switched entity.  If @code{OPTIMIZE_MODE_SWITCHING} is defined, you must define this macro to return an integer value not larger than the corresponding element in @code{NUM_MODES_FOR_MODE_SWITCHING}, to denote the mode that @var{entity} must be switched into prior to the execution of @var{insn}.",
  int, (int entity, rtx insn), NULL)
 
 DEFHOOK
Index: gcc/testsuite/gcc.target/sh/fpchg.c
===================================================================
--- gcc/testsuite/gcc.target/sh/fpchg.c	(revision 0)
+++ gcc/testsuite/gcc.target/sh/fpchg.c	(working copy)
@@ -0,0 +1,16 @@
+/* Check that fpchg is used to switch precision.  */
+
+/* { dg-do compile } */
+/* { dg-final { scan-assembler "fpchg" } } */
+/* { dg-final { scan-assembler-not "fpscr" } } */
+/* { dg-skip-if "" { "sh*-*-*" } { "*" } { "-m4a" } } */
+
+extern float c;
+
+void
+foo(int j)
+{
+  while (j--)
+    c++;
+
+}

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PING*2][PATCH] Extend mode-switching to support toggle (1/2)
  2014-05-26 15:32         ` Christian Bruel
@ 2014-06-02 12:34           ` Christian Bruel
  2014-06-11  4:17             ` Joern Rennecke
  0 siblings, 1 reply; 21+ messages in thread
From: Christian Bruel @ 2014-06-02 12:34 UTC (permalink / raw)
  To: Joern Rennecke, Jeff Law; +Cc: gcc-patches

Hello,

Any feedback for this ? I'd like to commit only when OK for Epiphany.

many thanks,

Christian

On 05/26/2014 05:32 PM, Christian Bruel wrote:
>> On 04/28/2014 10:08 AM, Christian Bruel wrote:
>>>>>> Hello,
>>>>>>
>>>>>> I'd like to ping the following patches
>>>>>>
>>>>>> [Hookize mode-switching]
>>>>>> http://gcc.gnu.org/ml/gcc-patches/2014-04/msg01003.html
>>>>>>
>>>>>> [Add new hooks to support toggle and SH4A fpchg instruction]
>>>>>> http://gcc.gnu.org/ml/gcc-patches/2014-04/msg01005.html
>>> Sorry, I only saw the first part and thought I' d need to wait till I
>>> see the second part - and I somehow missed that.
>>>
>>> I think the previous known mode should be passed to the
>>> TARGET_MODE_EMIT hook - no need to have extra hooks
>>> for toggling, and, as I mentioned earlier, fixating on the toggle is
>>> actually an SH artifact - other ports have multi-way
>>> modes settings that can benefit from knowing the previous mode.
>> OK I'll change the bool toggle parameter by the previous mode in
>> TARGET_MODE_EMIT and remove the bool XOR hooks in the SH description.
>>
> Hello,
>
> This is the interface for targets that could use the previous mode for
> switching. TARGET_MODE_EMIT now takes a new prev_mode parameter. If the
> previous mode cannot be determined, MODE_NONE (value depends on  the
> entity) is used.
>
> The implementation is less trivial than just supporting a boolean toggle
> bit, as the previous modes information have to be carried along the
> edges. For this I recycle the auxiliary edge field that is made
> unnecessary by the removal of make_pred_opaque and a change in the
> implementation to call LCM for every modes from every identity
> simultaneously. This idea was suggested by Joern in PR29349.  Another
> speed improvement is that we process the modes to no_mode instead of
> max_num_modes for each entity.
> Thanks to all this, the only additional data to support prev_mode is
> that for each BB, the avin/avout lcm computation are cached inside the
> bb_info mode_in/mode_out fields,  the xor toggle bit handling  could
> have been removed.
>
> bootstrapped/regtested for x86 and sh4, sh4a, sh4a-single,
> epiphany build is OK. testsuite not ran.
>
> Joern, is this new target macro interface OK with you ? Jeff, (or other
> RTL maintainer) since this is a new implementation for
> optimize_mode_switching I suppose your previous approval doesn't held
> anymore... is this new one OK for trunk as well ?
> No change for x86/sh4/2a interfaces.
>
> Many thanks
>
> Christian
>
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PING*2][PATCH] Extend mode-switching to support toggle (1/2)
  2014-05-13 21:41               ` Oleg Endo
@ 2014-06-10 14:03                 ` Joern Rennecke
  2014-06-11 12:40                   ` Christian Bruel
  0 siblings, 1 reply; 21+ messages in thread
From: Joern Rennecke @ 2014-06-10 14:03 UTC (permalink / raw)
  To: Oleg Endo; +Cc: Christian Bruel, GCC Patches, Jeff Law, Kaz Kojima

On 13 May 2014 22:41, Oleg Endo <oleg.endo@t-online.de> wrote:

> Right.  I was thinking to add FPSCR.SZ mode switching to SH, in order to
> do float vector moves.  For that SZ and PR need to be switched both at
> the same time (only SH4A has both, fpchg and fschg).  So basically I'd
> add another mode entity, which would emit SZ mode changes in addition to
> the PR mode changes.  But then adjacent FPSCR-changing insns could be
> combined ... any idea/suggestion how to accomplish that?

If they are sufficiently adjacent, you can use a peephole2 pattern for this.

I see Cristian's patch addresses this in a different way - keeping size and
precision in the same entity, and emitting toggles as appropriate.

The problem get's a bit more interesting if you have some instruction patterns
that care about one setting but not the other.
Describing this exactly allows lazy code motion to be a bit more lazy, but OTOH
it can make it harder to combine mode switching instructions if you
still want to
do that.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PING*2][PATCH] Extend mode-switching to support toggle (1/2)
  2014-06-02 12:34           ` Christian Bruel
@ 2014-06-11  4:17             ` Joern Rennecke
  2014-06-11 12:00               ` Christian Bruel
  0 siblings, 1 reply; 21+ messages in thread
From: Joern Rennecke @ 2014-06-11  4:17 UTC (permalink / raw)
  To: Christian Bruel; +Cc: Jeff Law, GCC Patches

[-- Attachment #1: Type: text/plain, Size: 905 bytes --]

On 2 June 2014 13:34, Christian Bruel <christian.bruel@st.com> wrote:
> Hello,
>
> Any feedback for this ? I'd like to commit only when OK for Epiphany.

>> Joern, is this new target macro interface OK with you ?

Yes, this interface should allow me to do switches between rounding
and truncating
floating-point modes with an add/subtract immediate.

However, the implentation, as posted, doesn't work - it causes memory
corruption.

It appears to work with the attached amendment patch.

                === gcc Summary ===

# of expected passes            82184
# of unexpected failures        41
# of unexpected successes       1
# of expected failures          90
# of unresolved testcases       2
# of unsupported tests          1585
/ssd/adapteva/bld-epiphany/gcc/xgcc  version 4.10.0 20140608
(experimental) (Epiphany toolchain (built 20140610))

This is the same as before applying the patch(es).

[-- Attachment #2: tmp --]
[-- Type: application/octet-stream, Size: 1676 bytes --]

--- gcc-20140610-1834//mode-switching.c	2014-06-10 14:46:06.072820132 +0100
+++ gcc/mode-switching.c	2014-06-10 18:55:57.282571137 +0100
@@ -120,9 +120,9 @@ get_mode_set (int e, edge eg)
 /* Allocate the modes area on edge EG. Initialized with -1.  */
 
 static void
-alloc_mode_aux (edge eg, int n_entities, int *entity_map)
+alloc_mode_aux (edge eg, int n_entities, int max_entity, int *entity_map)
 {
-  eg->aux = (int *)xmalloc (sizeof (int) *  n_entities);
+  eg->aux = (int *)xmalloc (sizeof (int) *  (max_entity + 1));
 
   for (int j = n_entities - 1; j >= 0; j--)
     add_mode_set (entity_map[j], eg,  -1);
@@ -533,6 +533,7 @@ optimize_mode_switching (void)
   struct bb_info *bb_info[N_ENTITIES];
   int i, j;
   int n_entities = 0;
+  int max_entity = -1;
   int max_num_modes = 0;
   bool emitted ATTRIBUTE_UNUSED = false;
   basic_block post_entry = 0;
@@ -548,6 +549,9 @@ optimize_mode_switching (void)
       {
 	int entry_exit_extra = 0;
 
+	if (e > max_entity)
+	  max_entity = e;
+
 	/* Create the list of segments within each basic block.
 	   If NORMAL_MODE is defined, allow for two extra
 	   blocks split from the entry and exit block.  */
@@ -757,6 +761,8 @@ optimize_mode_switching (void)
 	{
 	  edge eg = INDEX_EDGE (edge_list, ed);
 
+	  eg->aux = 0;
+
 	  for (i = 0; i < no_mode; i++)
 	    {
 	      int m = targetm.mode_switching.priority (entity_map[j], i);
@@ -766,7 +772,7 @@ optimize_mode_switching (void)
 
 	      /* Remember we need to emit it.  */
 	      if (!eg->aux)
-		alloc_mode_aux (eg, n_entities, entity_map);
+		alloc_mode_aux (eg, n_entities, max_entity, entity_map);
 	      add_mode_set (entity_map[j], eg, m);
 	    }
 	}

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PING*2][PATCH] Extend mode-switching to support toggle (1/2)
  2014-06-11  4:17             ` Joern Rennecke
@ 2014-06-11 12:00               ` Christian Bruel
  2014-06-12 14:35                 ` Christian Bruel
  0 siblings, 1 reply; 21+ messages in thread
From: Christian Bruel @ 2014-06-11 12:00 UTC (permalink / raw)
  To: Joern Rennecke; +Cc: Jeff Law, GCC Patches


On 06/11/2014 06:17 AM, Joern Rennecke wrote:
>
>>> Joern, is this new target macro interface OK with you ?
> Yes, this interface should allow me to do switches between rounding
> and truncating
> floating-point modes with an add/subtract immediate.
>
> However, the implentation, as posted, doesn't work - it causes memory
> corruption.
>
> It appears to work with the attached amendment patch.
>

Indeed,  thanks for pointing out the bad reusing of the aux field
between multiple entities.

In fact rereading this part of the implementation, I find the allocation
of aux*n_entities awkward. A simpler setting in the entity loop to carry
the mode directly into eg->aux is possible without array allocation
(which also fixes a memory leak by the way).

cheers,

Christian

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PING*2][PATCH] Extend mode-switching to support toggle (1/2)
  2014-06-10 14:03                 ` Joern Rennecke
@ 2014-06-11 12:40                   ` Christian Bruel
  2014-06-11 21:16                     ` Oleg Endo
  0 siblings, 1 reply; 21+ messages in thread
From: Christian Bruel @ 2014-06-11 12:40 UTC (permalink / raw)
  To: Joern Rennecke; +Cc: Oleg Endo, GCC Patches, Jeff Law, Kaz Kojima


On 06/10/2014 04:03 PM, Joern Rennecke wrote:
> On 13 May 2014 22:41, Oleg Endo <oleg.endo@t-online.de> wrote:
>
>> Right.  I was thinking to add FPSCR.SZ mode switching to SH, in order to
>> do float vector moves.  For that SZ and PR need to be switched both at
>> the same time (only SH4A has both, fpchg and fschg).  So basically I'd
>> add another mode entity, which would emit SZ mode changes in addition to
>> the PR mode changes.  But then adjacent FPSCR-changing insns could be
>> combined ... any idea/suggestion how to accomplish that?
> If they are sufficiently adjacent, you can use a peephole2 pattern for this.
>
> I see Cristian's patch addresses this in a different way - keeping size and
> precision in the same entity, and emitting toggles as appropriate.

yes, I was only interested to optimize the SH4a case when PR=1 with a
good enough implementation. To cover all the other possibilities a new
entity would be better. But then as you say recombining them might be
difficult.  An alternate hackish way could be to have a singe entity
with 4 modes covering all PR*SZ combinations).

but I'm not sure that covering the case where PR=0 SZ=1 worth it, maybe
code size only, ? as the 64 move would be implemented as 2*32 moves anyway,

>
> The problem get's a bit more interesting if you have some instruction patterns
> that care about one setting but not the other.
> Describing this exactly allows lazy code motion to be a bit more lazy, but OTOH
> it can make it harder to combine mode switching instructions if you
> still want to
> do that.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PING*2][PATCH] Extend mode-switching to support toggle (1/2)
  2014-06-11 12:40                   ` Christian Bruel
@ 2014-06-11 21:16                     ` Oleg Endo
  0 siblings, 0 replies; 21+ messages in thread
From: Oleg Endo @ 2014-06-11 21:16 UTC (permalink / raw)
  To: Christian Bruel; +Cc: Joern Rennecke, GCC Patches, Jeff Law, Kaz Kojima


On 11 Jun 2014, at 14:40, Christian Bruel <christian.bruel@st.com> wrote:

> 
> On 06/10/2014 04:03 PM, Joern Rennecke wrote:
>> On 13 May 2014 22:41, Oleg Endo <oleg.endo@t-online.de> wrote:
>> 
>>> Right.  I was thinking to add FPSCR.SZ mode switching to SH, in order to
>>> do float vector moves.  For that SZ and PR need to be switched both at
>>> the same time (only SH4A has both, fpchg and fschg).  So basically I'd
>>> add another mode entity, which would emit SZ mode changes in addition to
>>> the PR mode changes.  But then adjacent FPSCR-changing insns could be
>>> combined ... any idea/suggestion how to accomplish that?
>> If they are sufficiently adjacent, you can use a peephole2 pattern for this.
>> 
>> I see Cristian's patch addresses this in a different way - keeping size and
>> precision in the same entity, and emitting toggles as appropriate.
> 
> yes, I was only interested to optimize the SH4a case when PR=1 with a
> good enough implementation. To cover all the other possibilities a new
> entity would be better. But then as you say recombining them might be
> difficult.  An alternate hackish way could be to have a singe entity
> with 4 modes covering all PR*SZ combinations).
> 
> but I'm not sure that covering the case where PR=0 SZ=1 worth it, maybe
> code size only, ? as the 64 move would be implemented as 2*32 moves anyway,

I was thinking of using PR=0,SZ=1 mode (i.e. fmov.d) for float vector loads/stores.  But at the moment that's a pie in the sky.

Cheers,
Oleg

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PING*2][PATCH] Extend mode-switching to support toggle (1/2)
  2014-06-11 12:00               ` Christian Bruel
@ 2014-06-12 14:35                 ` Christian Bruel
  2014-06-17 21:19                   ` Jeff Law
  0 siblings, 1 reply; 21+ messages in thread
From: Christian Bruel @ 2014-06-12 14:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jeff Law, Joern Rennecke

[-- Attachment #1: Type: text/plain, Size: 1124 bytes --]

On 06/11/2014 02:00 PM, Christian Bruel wrote:
> On 06/11/2014 06:17 AM, Joern Rennecke wrote:
>>>> Joern, is this new target macro interface OK with you ?
>> Yes, this interface should allow me to do switches between rounding
>> and truncating
>> floating-point modes with an add/subtract immediate.
>>
>> However, the implentation, as posted, doesn't work - it causes memory
>> corruption.
>>
>> It appears to work with the attached amendment patch.
>>
> Indeed,  thanks for pointing out the bad reusing of the aux field
> between multiple entities.
>
> In fact rereading this part of the implementation, I find the allocation
> of aux*n_entities awkward. A simpler setting in the entity loop to carry
> the mode directly into eg->aux is possible without array allocation
> (which also fixes a memory leak by the way).
>

Here is the revised version fixing the aforementioned issue found by
Joern on Epiphany. It also simplifies the allocation of the aux edges
field to carry the modes.

Now that everyone agrees on the interface, is this OK for trunk ?

bootstrapped/regtested for X86 and SH4a.

thanks,

Christian







[-- Attachment #2: toggle.patch --]
[-- Type: text/x-patch, Size: 29659 bytes --]

2014-06-12  Christian Bruel  <christian.bruel@st.com>

	* mode-switching.c (struct bb_info): Add mode_out, mode_in caches.
	(make_preds_opaque): Delete.
	(clear_mode_bit, mode_bit_p, set_mode_bit): New macros.
	(commit_mode_sets): New function.
	(optimize_mode_switching): Handle current_mode to mode_switching_emit.
	Process all modes at once.
	* basic-block.h (pre_edge_lcm_avs): Declare.
	* lcm.c (pre_edge_lcm_avs): Renamed from pre_edge_lcm.
	Call clear_aux_for_edges. Fix comments.
	(pre_edge_lcm): New wrapper function to call pre_edge_lcm_avs.
	(pre_edge_rev_lcm): Idem.
	* config/epiphany/epiphany.c (emit_set_fp_mode): Add prev_mode parameter.
	* config/epiphany/epiphany-protos.h (emit_set_fp_mode): Idem.
	* config/epiphany/resolve-sw-modes.c (pass_resolve_sw_modes::execute): Idem.
	* config/i386/i386.c (x96_emit_mode_set): Idem.
	* config/sh/sh.c (sh_emit_mode_set): Likewise. Handle PR toggle.
	* config/sh/sh.md (toggle_pr): 	Defined if TARGET_FPU_SINGLE.
	(fpscr_toggle) Disallow from delay slot.
	* target.def (emit_mode_set): Add prev_mode parameter.
	* doc/tm.texi: Regenerate.

2014-06-12  Christian Bruel  <christian.bruel@st.com>

	* gcc.target/sh/fpchg.c: New test.

Index: gcc/basic-block.h
===================================================================
--- gcc/basic-block.h	(revision 211436)
+++ gcc/basic-block.h	(working copy)
@@ -711,6 +711,9 @@ extern void bitmap_union_of_preds (sbitmap, sbitma
 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 **,
Index: gcc/config/epiphany/epiphany-protos.h
===================================================================
--- gcc/config/epiphany/epiphany-protos.h	(revision 211436)
+++ gcc/config/epiphany/epiphany-protos.h	(working copy)
@@ -40,7 +40,8 @@ extern int epiphany_initial_elimination_offset (in
 extern void epiphany_init_expanders (void);
 extern int hard_regno_mode_ok (int regno, enum machine_mode mode);
 #ifdef HARD_CONST
-extern void emit_set_fp_mode (int entity, int mode, HARD_REG_SET regs_live);
+extern void emit_set_fp_mode (int entity, int mode, int prev_mode,
+			      HARD_REG_SET regs_live);
 #endif
 extern void epiphany_insert_mode_switch_use (rtx insn, int, int);
 extern void epiphany_expand_set_fp_mode (rtx *operands);
Index: gcc/config/epiphany/epiphany.c
===================================================================
--- gcc/config/epiphany/epiphany.c	(revision 211436)
+++ gcc/config/epiphany/epiphany.c	(working copy)
@@ -2543,7 +2543,8 @@ epiphany_mode_exit (int entity)
 }
 
 void
-emit_set_fp_mode (int entity, int mode, HARD_REG_SET regs_live ATTRIBUTE_UNUSED)
+emit_set_fp_mode (int entity, int mode, int prev_mode ATTRIBUTE_UNUSED,
+		  HARD_REG_SET regs_live ATTRIBUTE_UNUSED)
 {
   rtx save_cc, cc_reg, mask, src, src2;
   enum attr_fp_mode fp_mode;
Index: gcc/config/epiphany/resolve-sw-modes.c
===================================================================
--- gcc/config/epiphany/resolve-sw-modes.c	(revision 211436)
+++ gcc/config/epiphany/resolve-sw-modes.c	(working copy)
@@ -170,7 +170,7 @@ pass_resolve_sw_modes::execute (function *fun)
 	    }
 	  start_sequence ();
 	  emit_set_fp_mode (EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN,
-			    jilted_mode, NULL);
+			    jilted_mode, FP_MODE_NONE, NULL);
 	  seq = get_insns ();
 	  end_sequence ();
 	  need_commit = true;
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c	(revision 211436)
+++ gcc/config/i386/i386.c	(working copy)
@@ -16447,7 +16447,8 @@ ix86_avx_emit_vzeroupper (HARD_REG_SET regs_live)
    are to be inserted.  */
 
 static void
-ix86_emit_mode_set (int entity, int mode, HARD_REG_SET regs_live)
+ix86_emit_mode_set (int entity, int mode, int prev_mode ATTRIBUTE_UNUSED,
+		    HARD_REG_SET regs_live)
 {
   switch (entity)
     {
Index: gcc/config/sh/sh.c
===================================================================
--- gcc/config/sh/sh.c	(revision 211436)
+++ gcc/config/sh/sh.c	(working copy)
@@ -203,7 +203,7 @@ static void push_regs (HARD_REG_SET *, int);
 static int calc_live_regs (HARD_REG_SET *);
 static HOST_WIDE_INT rounded_frame_size (int);
 static bool sh_frame_pointer_required (void);
-static void sh_emit_mode_set (int, int, HARD_REG_SET);
+static void sh_emit_mode_set (int, int, int, HARD_REG_SET);
 static int sh_mode_needed (int, rtx);
 static int sh_mode_after (int, int, rtx);
 static int sh_mode_entry (int);
@@ -13582,9 +13582,17 @@ sh_try_omit_signzero_extend (rtx extended_op, rtx
 
 static void
 sh_emit_mode_set (int entity ATTRIBUTE_UNUSED, int mode,
-		  HARD_REG_SET regs_live)
+		  int prev_mode, HARD_REG_SET regs_live)
 {
-  fpscr_set_from_mem (mode, regs_live);
+  if ((TARGET_SH4A_FP || TARGET_SH4_300)
+      && prev_mode != FP_MODE_NONE && prev_mode != mode)
+    {
+      emit_insn (gen_toggle_pr ());
+      if (TARGET_FMOVD)
+	emit_insn (gen_toggle_sz ());
+    }
+  else
+    fpscr_set_from_mem (mode, regs_live);
 }
 
 static int
Index: gcc/config/sh/sh.md
===================================================================
--- gcc/config/sh/sh.md	(revision 211436)
+++ gcc/config/sh/sh.md	(working copy)
@@ -504,6 +504,7 @@
 (define_attr "in_delay_slot" "yes,no"
   (cond [(eq_attr "type" "cbranch") (const_string "no")
 	 (eq_attr "type" "pcload,pcload_si") (const_string "no")
+	 (eq_attr "type" "fpscr_toggle") (const_string "no")
 	 (eq_attr "needs_delay_slot" "yes") (const_string "no")
 	 (eq_attr "length" "2") (const_string "yes")
 	 ] (const_string "no")))
@@ -12239,15 +12240,12 @@ label:
   "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).
+;; Toggle FPU precision PR mode.
+
 (define_insn "toggle_pr"
   [(set (reg:PSI FPSCR_REG)
 	(xor:PSI (reg:PSI FPSCR_REG) (const_int 524288)))]
-  "TARGET_SH4A_FP && ! TARGET_FPU_SINGLE"
+  "TARGET_SH4A_FP"
   "fpchg"
   [(set_attr "type" "fpscr_toggle")])
 
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi	(revision 211436)
+++ gcc/doc/tm.texi	(working copy)
@@ -9595,12 +9595,12 @@ represented as numbers 0 @dots{} N @minus{} 1.  N
 switch is needed / supplied.
 @end defmac
 
-@deftypefn {Target Hook} void TARGET_MODE_EMIT (int @var{entity}, int @var{mode}, HARD_REG_SET @var{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. Sets of a lower numbered entity will be emitted before sets of a higher numbered entity to a mode of the same or lower priority.
+@deftypefn {Target Hook} void TARGET_MODE_EMIT (int @var{entity}, int @var{mode}, int @var{prev_mode}, HARD_REG_SET @var{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{prev_moxde} indicates the mode to switch from. Sets of a lower numbered entity will be emitted before sets of a higher numbered entity to a mode of the same or lower priority.
 @end deftypefn
 
 @deftypefn {Target Hook} int TARGET_MODE_NEEDED (int @var{entity}, rtx @var{insn})
-@var{entity} is an integer specifying a mode-switched entity. If @code{OPTIMIZE_MODE_SWITCHING} is defined, you must define this macro to return an integer value not larger than the corresponding element in @code{NUM_MODES_FOR_MODE_SWITCHING}, to denote the mode that @var{entity} must be switched into prior to the execution of @var{insn}.
+@var{entity} is an integer specifying a mode-switched entity.  If @code{OPTIMIZE_MODE_SWITCHING} is defined, you must define this macro to return an integer value not larger than the corresponding element in @code{NUM_MODES_FOR_MODE_SWITCHING}, to denote the mode that @var{entity} must be switched into prior to the execution of @var{insn}.
 @end deftypefn
 
 @deftypefn {Target Hook} int TARGET_MODE_AFTER (int @var{entity}, int @var{mode}, rtx @var{insn})
Index: gcc/lcm.c
===================================================================
--- gcc/lcm.c	(revision 211436)
+++ gcc/lcm.c	(working copy)
@@ -377,17 +377,17 @@ compute_insert_delete (struct edge_list *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
+/* Given local properties TRANSP, ANTLOC, AVLOC, KILL return the insert and
+   delete vectors for edge based LCM  and return the AVIN, AVOUT bitmap.
    map the insert vector to what edge an expression should be inserted on.  */
 
 struct edge_list *
-pre_edge_lcm (int n_exprs, sbitmap *transp,
+pre_edge_lcm_avs (int n_exprs, sbitmap *transp,
 	      sbitmap *avloc, sbitmap *antloc, sbitmap *kill,
+	      sbitmap *avin, sbitmap *avout,
 	      sbitmap **insert, sbitmap **del)
 {
   sbitmap *antin, *antout, *earliest;
-  sbitmap *avin, *avout;
   sbitmap *later, *laterin;
   struct edge_list *edge_list;
   int num_edges;
@@ -413,10 +413,7 @@ struct edge_list *
 #endif
 
   /* Compute global availability.  */
-  avin = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_exprs);
-  avout = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_exprs);
   compute_available (avloc, kill, avout, avin);
-  sbitmap_vector_free (avin);
 
   /* Compute global anticipatability.  */
   antin = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_exprs);
@@ -444,7 +441,6 @@ struct edge_list *
 
   sbitmap_vector_free (antout);
   sbitmap_vector_free (antin);
-  sbitmap_vector_free (avout);
 
   later = sbitmap_vector_alloc (num_edges, n_exprs);
 
@@ -485,6 +481,28 @@ struct edge_list *
   return edge_list;
 }
 
+/* Wrapper to allocate avin/avout and call pre_edge_lcm_avs.  */
+
+struct edge_list *
+pre_edge_lcm (int n_exprs, sbitmap *transp,
+	      sbitmap *avloc, sbitmap *antloc, sbitmap *kill,
+	      sbitmap **insert, sbitmap **del)
+{
+  struct edge_list *edge_list;
+  sbitmap *avin, *avout;
+
+  avin = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_exprs);
+  avout = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_exprs);
+
+  edge_list = pre_edge_lcm_avs (n_exprs, transp, avloc, antloc, kill,
+				 avin, avout, insert, del);
+
+  sbitmap_vector_free (avout);
+  sbitmap_vector_free (avin);
+
+  return edge_list;
+}
+
 /* Compute the AVIN and AVOUT vectors from the AVLOC and KILL vectors.
    Return the number of passes we performed to iterate to a solution.  */
 
Index: gcc/mode-switching.c
===================================================================
--- gcc/mode-switching.c	(revision 211436)
+++ gcc/mode-switching.c	(working copy)
@@ -80,23 +80,75 @@ struct bb_info
 {
   struct seginfo *seginfo;
   int computing;
+  int mode_out;
+  int mode_in;
 };
 
-/* These bitmaps are used for the LCM algorithm.  */
-
-static sbitmap *antic;
-static sbitmap *transp;
-static sbitmap *comp;
-
 static struct seginfo * new_seginfo (int, rtx, int, HARD_REG_SET);
 static void add_seginfo (struct bb_info *, struct seginfo *);
 static void reg_dies (rtx, HARD_REG_SET *);
 static void reg_becomes_live (rtx, const_rtx, void *);
-static void make_preds_opaque (basic_block, int);
-\f
 
-/* This function will allocate a new BBINFO structure, initialized
-   with the MODE, INSN, and basic block BB parameters.
+/* Clear ode I from entity J in bitmap B.  */
+#define clear_mode_bit(b, j, i) \
+       bitmap_clear_bit (b, (j * max_num_modes) + i)
+
+/* Test mode I from entity J in bitmap B.  */
+#define mode_bit_p(b, j, i) \
+       bitmap_bit_p (b, (j * max_num_modes) + i)
+
+/* Set mode I from entity J in bitmal B.  */
+#define set_mode_bit(b, j, i) \
+       bitmap_set_bit (b, (j * max_num_modes) + i)
+
+/* Emit modes segments from EDGE_LIST associated with entity E.
+   INFO gives mode availability for each mode.  */
+
+static bool
+commit_mode_sets (struct edge_list *edge_list, int e, struct bb_info *info)
+{
+  bool need_commit = false;
+
+  for (int ed = NUM_EDGES (edge_list) - 1; ed >= 0; ed--)
+    {
+      edge eg = INDEX_EDGE (edge_list, ed);
+      int mode;
+
+      if ((mode = (int)(intptr_t)(eg->aux)) != -1)
+	{
+	  HARD_REG_SET live_at_edge;
+	  basic_block src_bb = eg->src;
+	  int cur_mode = info[src_bb->index].mode_out;
+	  rtx mode_set;
+
+	  REG_SET_TO_HARD_REG_SET (live_at_edge, df_get_live_out (src_bb));
+
+	  rtl_profile_for_edge (eg);
+	  start_sequence ();
+
+	  targetm.mode_switching.emit (e, mode, cur_mode, live_at_edge);
+
+	  mode_set = get_insns ();
+	  end_sequence ();
+	  default_rtl_profile ();
+
+	  /* 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 = true;
+	  insert_insn_on_edge (mode_set, eg);
+	}
+    }
+
+  return need_commit;
+}
+
+/* Allocate a new BBINFO structure, initialized with the MODE, INSN,
+   and basic block BB parameters.
    INSN may not be a NOTE_INSN_BASIC_BLOCK, unless it is an empty
    basic block; that allows us later to insert instructions in a FIFO-like
    manner.  */
@@ -137,30 +189,6 @@ add_seginfo (struct bb_info *head, struct seginfo
     }
 }
 
-/* Make all predecessors of basic block B opaque, recursively, till we hit
-   some that are already non-transparent, or an edge where aux is set; that
-   denotes that a mode set is to be done on that edge.
-   J is the bit number in the bitmaps that corresponds to the entity that
-   we are currently handling mode-switching for.  */
-
-static void
-make_preds_opaque (basic_block b, int j)
-{
-  edge e;
-  edge_iterator ei;
-
-  FOR_EACH_EDGE (e, ei, b->preds)
-    {
-      basic_block pb = e->src;
-
-      if (e->aux || ! bitmap_bit_p (transp[pb->index], j))
-	continue;
-
-      bitmap_clear_bit (transp[pb->index], j);
-      make_preds_opaque (pb, j);
-    }
-}
-
 /* Record in LIVE that register REG died.  */
 
 static void
@@ -452,24 +480,26 @@ create_pre_exit (int n_entities, int *entity_map,
 static int
 optimize_mode_switching (void)
 {
-  rtx insn;
   int e;
   basic_block bb;
-  int need_commit = 0;
-  sbitmap *kill;
-  struct edge_list *edge_list;
+  bool need_commit = false;
   static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING;
 #define N_ENTITIES ARRAY_SIZE (num_modes)
   int entity_map[N_ENTITIES];
   struct bb_info *bb_info[N_ENTITIES];
   int i, j;
-  int n_entities;
+  int n_entities = 0;
   int max_num_modes = 0;
   bool emitted ATTRIBUTE_UNUSED = false;
   basic_block post_entry = 0;
   basic_block pre_exit = 0;
+  struct edge_list *edge_list = 0;
 
-  for (e = N_ENTITIES - 1, n_entities = 0; e >= 0; e--)
+  /* These bitmaps are used for the LCM algorithm.  */
+  sbitmap *kill, *del, *insert, *antic, *transp, *comp;
+  sbitmap *avin, *avout;
+
+  for (e = N_ENTITIES - 1; e >= 0; e--)
     if (OPTIMIZE_MODE_SWITCHING (e))
       {
 	int entry_exit_extra = 0;
@@ -491,9 +521,10 @@ optimize_mode_switching (void)
   if (! n_entities)
     return 0;
 
-  /* Make sure if MODE_ENTRY is defined the MODE_EXIT is defined and vice versa.  */
+  /* Make sure if MODE_ENTRY is defined MODE_EXIT is defined.  */
   gcc_assert ((targetm.mode_switching.entry && targetm.mode_switching.exit)
-	      || (!targetm.mode_switching.entry && !targetm.mode_switching.exit));
+	      || (!targetm.mode_switching.entry
+		  && !targetm.mode_switching.exit));
 
   if (targetm.mode_switching.entry && targetm.mode_switching.exit)
     {
@@ -506,18 +537,29 @@ optimize_mode_switching (void)
   df_analyze ();
 
   /* Create the bitmap vectors.  */
+  antic = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
+				n_entities * max_num_modes);
+  transp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
+				 n_entities * max_num_modes);
+  comp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
+			       n_entities * max_num_modes);
+  avin = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
+			       n_entities * max_num_modes);
+  avout = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
+				n_entities * max_num_modes);
+  kill = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
+			       n_entities * max_num_modes);
 
-  antic = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_entities);
-  transp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_entities);
-  comp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_entities);
-
   bitmap_vector_ones (transp, last_basic_block_for_fn (cfun));
+  bitmap_vector_clear (antic, last_basic_block_for_fn (cfun));
+  bitmap_vector_clear (comp, last_basic_block_for_fn (cfun));
 
   for (j = n_entities - 1; j >= 0; j--)
     {
       int e = entity_map[j];
       int no_mode = num_modes[e];
       struct bb_info *info = bb_info[j];
+      rtx insn;
 
       /* Determine what the first use (if any) need for a mode of entity E is.
 	 This will be the mode that is anticipatable for this block.
@@ -529,16 +571,18 @@ optimize_mode_switching (void)
 	  bool any_set_required = false;
 	  HARD_REG_SET live_now;
 
+	  info[bb->index].mode_out = info[bb->index].mode_in = no_mode;
+
 	  REG_SET_TO_HARD_REG_SET (live_now, df_get_live_in (bb));
 
 	  /* Pretend the mode is clobbered across abnormal edges.  */
 	  {
 	    edge_iterator ei;
-	    edge e;
-	    FOR_EACH_EDGE (e, ei, bb->preds)
-	      if (e->flags & EDGE_COMPLEX)
+	    edge eg;
+	    FOR_EACH_EDGE (eg, ei, bb->preds)
+	      if (eg->flags & EDGE_COMPLEX)
 		break;
-	    if (e)
+	    if (eg)
 	      {
 		rtx ins_pos = BB_HEAD (bb);
 		if (LABEL_P (ins_pos))
@@ -548,7 +592,8 @@ optimize_mode_switching (void)
 		  ins_pos = NEXT_INSN (ins_pos);
 		ptr = new_seginfo (no_mode, ins_pos, bb->index, live_now);
 		add_seginfo (info + bb->index, ptr);
-		bitmap_clear_bit (transp[bb->index], j);
+		for (i = 0; i < no_mode; i++)
+		  clear_mode_bit (transp[bb->index], j, i);
 	      }
 	  }
 
@@ -565,11 +610,13 @@ optimize_mode_switching (void)
 		      last_mode = mode;
 		      ptr = new_seginfo (mode, insn, bb->index, live_now);
 		      add_seginfo (info + bb->index, ptr);
-		      bitmap_clear_bit (transp[bb->index], j);
+		      for (i = 0; i < no_mode; i++)
+			clear_mode_bit (transp[bb->index], j, i);
 		    }
 
 		  if (targetm.mode_switching.after)
-		    last_mode = targetm.mode_switching.after (e, last_mode, insn);
+		    last_mode = targetm.mode_switching.after (e, last_mode,
+							      insn);
 
 		  /* Update LIVE_NOW.  */
 		  for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
@@ -593,13 +640,22 @@ optimize_mode_switching (void)
 	      ptr = new_seginfo (no_mode, BB_END (bb), bb->index, live_now);
 	      add_seginfo (info + bb->index, ptr);
 	      if (last_mode != no_mode)
-		bitmap_clear_bit (transp[bb->index], j);
+		for (i = 0; i < no_mode; i++)
+		  clear_mode_bit (transp[bb->index], j, i);
 	    }
 	}
       if (targetm.mode_switching.entry && targetm.mode_switching.exit)
 	{
 	  int mode = targetm.mode_switching.entry (e);
 
+	  info[post_entry->index].mode_out =
+	    info[post_entry->index].mode_in = no_mode;
+	  if (pre_exit)
+	    {
+	      info[pre_exit->index].mode_out =
+		info[pre_exit->index].mode_in = no_mode;
+	    }
+
 	  if (mode != no_mode)
 	    {
 	      bb = post_entry;
@@ -608,7 +664,8 @@ optimize_mode_switching (void)
 		 an extra check in make_preds_opaque.  We also
 		 need this to avoid confusing pre_edge_lcm when
 		 antic is cleared but transp and comp are set.  */
-	      bitmap_clear_bit (transp[bb->index], j);
+	      for (i = 0; i < no_mode; i++)
+		clear_mode_bit (transp[bb->index], j, i);
 
 	      /* Insert a fake computing definition of MODE into entry
 		 blocks which compute no mode. This represents the mode on
@@ -620,115 +677,109 @@ optimize_mode_switching (void)
 		  targetm.mode_switching.exit (e);
 	    }
 	}
-    }
 
-  kill = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_entities);
-  for (i = 0; i < max_num_modes; i++)
-    {
-      int current_mode[N_ENTITIES];
-      sbitmap *del;
-      sbitmap *insert;
-
       /* Set the anticipatable and computing arrays.  */
-      bitmap_vector_clear (antic, last_basic_block_for_fn (cfun));
-      bitmap_vector_clear (comp, last_basic_block_for_fn (cfun));
-      for (j = n_entities - 1; j >= 0; j--)
+      for (i = 0; i < no_mode; i++)
 	{
-	  int m = current_mode[j] =
-	    targetm.mode_switching.priority (entity_map[j], i);
-	  struct bb_info *info = bb_info[j];
+	  int m = targetm.mode_switching.priority (entity_map[j], i);
 
 	  FOR_EACH_BB_FN (bb, cfun)
 	    {
 	      if (info[bb->index].seginfo->mode == m)
-		bitmap_set_bit (antic[bb->index], j);
+		set_mode_bit (antic[bb->index], j, m);
 
 	      if (info[bb->index].computing == m)
-		bitmap_set_bit (comp[bb->index], j);
+		set_mode_bit (comp[bb->index], j, m);
 	    }
 	}
+    }
 
-      /* Calculate the optimal locations for the
-	 placement mode switches to modes with priority I.  */
+  /* Calculate the optimal locations for the
+     placement mode switches to modes with priority I.  */
 
-      FOR_EACH_BB_FN (bb, cfun)
-	bitmap_not (kill[bb->index], transp[bb->index]);
-      edge_list = pre_edge_lcm (n_entities, transp, comp, antic,
-				kill, &insert, &del);
+  FOR_EACH_BB_FN (bb, cfun)
+    bitmap_not (kill[bb->index], transp[bb->index]);
 
-      for (j = n_entities - 1; j >= 0; j--)
-	{
-	  /* Insert all mode sets that have been inserted by lcm.  */
-	  int no_mode = num_modes[entity_map[j]];
+  edge_list = pre_edge_lcm_avs (n_entities * max_num_modes, transp, comp, antic,
+				kill, avin, avout, &insert, &del);
 
-	  /* Wherever we have moved a mode setting upwards in the flow graph,
-	     the blocks between the new setting site and the now redundant
-	     computation ceases to be transparent for any lower-priority
-	     mode of the same entity.  First set the aux field of each
-	     insertion site edge non-transparent, then propagate the new
-	     non-transparency from the redundant computation upwards till
-	     we hit an insertion site or an already non-transparent block.  */
-	  for (e = NUM_EDGES (edge_list) - 1; e >= 0; e--)
-	    {
-	      edge eg = INDEX_EDGE (edge_list, e);
-	      int mode;
-	      basic_block src_bb;
-	      HARD_REG_SET live_at_edge;
-	      rtx mode_set;
+  for (j = n_entities - 1; j >= 0; j--)
+    {
+      int no_mode = num_modes[entity_map[j]];
 
-	      eg->aux = 0;
+      /* Insert all mode sets that have been inserted by lcm.  */
 
-	      if (! bitmap_bit_p (insert[e], j))
-		continue;
+      for (int ed = NUM_EDGES (edge_list) - 1; ed >= 0; ed--)
+	{
+	  edge eg = INDEX_EDGE (edge_list, ed);
 
-	      eg->aux = (void *)1;
+	  eg->aux = (void *)(intptr_t)-1;
 
-	      mode = current_mode[j];
-	      src_bb = eg->src;
+	  for (i = 0; i < no_mode; i++)
+	    {
+	      int m = targetm.mode_switching.priority (entity_map[j], i);
+	      if (mode_bit_p (insert[ed], j, m))
+		{
+		  eg->aux = (void *)(intptr_t)m;
+		  break;
+		}
+	    }
+	}
 
-	      REG_SET_TO_HARD_REG_SET (live_at_edge, df_get_live_out (src_bb));
+      FOR_EACH_BB_FN (bb, cfun)
+	{
+	  struct bb_info *info = bb_info[j];
+	  int last_mode = no_mode;
 
-	      rtl_profile_for_edge (eg);
-	      start_sequence ();
-	      targetm.mode_switching.emit (entity_map[j], mode, live_at_edge);
-	      mode_set = get_insns ();
-	      end_sequence ();
-	      default_rtl_profile ();
+	  /* intialize mode in availability for bb.  */
+	  for (i = 0; i < no_mode; i++)
+	    if (mode_bit_p (avout[bb->index], j, i))
+	      {
+		if (last_mode == no_mode)
+		  last_mode = i;
+		if (last_mode != i)
+		  {
+		    last_mode = no_mode;
+		    break;
+		  }
+	      }
+	  info[bb->index].mode_out = last_mode;
 
-	      /* 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_FN (bb, cfun)
-	    if (bitmap_bit_p (del[bb->index], j))
+	  /* intialize mode out availability for bb.  */
+	  last_mode = no_mode;
+	  for (i = 0; i < no_mode; i++)
+	    if (mode_bit_p (avin[bb->index], j, i))
 	      {
-		make_preds_opaque (bb, j);
-		/* Cancel the 'deleted' mode set.  */
-		bb_info[j][bb->index].seginfo->mode = no_mode;
+		if (last_mode == no_mode)
+		  last_mode = i;
+		if (last_mode != i)
+		  {
+		    last_mode = no_mode;
+		    break;
+		  }
 	      }
+	  info[bb->index].mode_in = last_mode;
+
+	  for (i = 0; i < no_mode; i++)
+	    if (mode_bit_p (del[bb->index], j, i))
+	      info[bb->index].seginfo->mode = no_mode;
 	}
 
-      sbitmap_vector_free (del);
-      sbitmap_vector_free (insert);
+      /* Now output the remaining mode sets in all the segments.  */
+
+      /* 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.  */
+      need_commit |= commit_mode_sets (edge_list, entity_map[j], bb_info[j]);
+
+      /* Reset modes for next entity.  */
       clear_aux_for_edges ();
-      free_edge_list (edge_list);
-    }
 
-  /* Now output the remaining mode sets in all the segments.  */
-  for (j = n_entities - 1; j >= 0; j--)
-    {
-      int no_mode = num_modes[entity_map[j]];
-
-      FOR_EACH_BB_REVERSE_FN (bb, cfun)
+      FOR_EACH_BB_FN (bb, cfun)
 	{
 	  struct seginfo *ptr, *next;
+	  int cur_mode = bb_info[j][bb->index].mode_in;
+
 	  for (ptr = bb_info[j][bb->index].seginfo; ptr; ptr = next)
 	    {
 	      next = ptr->next;
@@ -738,12 +789,15 @@ optimize_mode_switching (void)
 
 		  rtl_profile_for_bb (bb);
 		  start_sequence ();
-		  targetm.mode_switching.emit (entity_map[j],
-					       ptr->mode,
-					       ptr->regs_live);
+
+		  targetm.mode_switching.emit (entity_map[j], ptr->mode,
+					       cur_mode, ptr->regs_live);
 		  mode_set = get_insns ();
 		  end_sequence ();
 
+		  /* modes kill each other inside a basic block.  */
+		  cur_mode = ptr->mode;
+
 		  /* Insert MODE_SET only if it is nonempty.  */
 		  if (mode_set != NULL_RTX)
 		    {
@@ -772,11 +826,17 @@ optimize_mode_switching (void)
       free (bb_info[j]);
     }
 
+  free_edge_list (edge_list);
+
   /* Finished. Free up all the things we've allocated.  */
+  sbitmap_vector_free (del);
+  sbitmap_vector_free (insert);
   sbitmap_vector_free (kill);
   sbitmap_vector_free (antic);
   sbitmap_vector_free (transp);
   sbitmap_vector_free (comp);
+  sbitmap_vector_free (avin);
+  sbitmap_vector_free (avout);
 
   if (need_commit)
     commit_edge_insertions ();
Index: gcc/target.def
===================================================================
--- gcc/target.def	(revision 211436)
+++ gcc/target.def	(working copy)
@@ -5365,12 +5365,12 @@ HOOK_VECTOR (TARGET_TOGGLE_, mode_switching)
 
 DEFHOOK
 (emit,
- "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. Sets of a lower numbered entity will be emitted before sets of a higher numbered entity to a mode of the same or lower priority.",
- void, (int entity, int mode, HARD_REG_SET regs_live), NULL)
+ "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{prev_moxde} indicates the mode to switch from. Sets of a lower numbered entity will be emitted before sets of a higher numbered entity to a mode of the same or lower priority.",
+ void, (int entity, int mode, int prev_mode, HARD_REG_SET regs_live), NULL)
 
 DEFHOOK
 (needed,
- "@var{entity} is an integer specifying a mode-switched entity. If @code{OPTIMIZE_MODE_SWITCHING} is defined, you must define this macro to return an integer value not larger than the corresponding element in @code{NUM_MODES_FOR_MODE_SWITCHING}, to denote the mode that @var{entity} must be switched into prior to the execution of @var{insn}.",
+ "@var{entity} is an integer specifying a mode-switched entity.  If @code{OPTIMIZE_MODE_SWITCHING} is defined, you must define this macro to return an integer value not larger than the corresponding element in @code{NUM_MODES_FOR_MODE_SWITCHING}, to denote the mode that @var{entity} must be switched into prior to the execution of @var{insn}.",
  int, (int entity, rtx insn), NULL)
 
 DEFHOOK
Index: gcc/testsuite/gcc.target/sh/fpchg.c
===================================================================
--- gcc/testsuite/gcc.target/sh/fpchg.c	(revision 0)
+++ gcc/testsuite/gcc.target/sh/fpchg.c	(working copy)
@@ -0,0 +1,16 @@
+/* Check that fpchg is used to switch precision.  */
+
+/* { dg-do compile } */
+/* { dg-final { scan-assembler "fpchg" } } */
+/* { dg-final { scan-assembler-not "fpscr" } } */
+/* { dg-skip-if "" { "sh*-*-*" } { "*" } { "-m4a" } } */
+
+extern float c;
+
+void
+foo(int j)
+{
+  while (j--)
+    c++;
+
+}

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PING*2][PATCH] Extend mode-switching to support toggle (1/2)
  2014-06-12 14:35                 ` Christian Bruel
@ 2014-06-17 21:19                   ` Jeff Law
  0 siblings, 0 replies; 21+ messages in thread
From: Jeff Law @ 2014-06-17 21:19 UTC (permalink / raw)
  To: Christian Bruel, gcc-patches; +Cc: Joern Rennecke

On 06/12/14 08:34, Christian Bruel wrote:
> On 06/11/2014 02:00 PM, Christian Bruel wrote:
>> >On 06/11/2014 06:17 AM, Joern Rennecke wrote:
>>>>> >>>>Joern, is this new target macro interface OK with you ?
>>> >>Yes, this interface should allow me to do switches between rounding
>>> >>and truncating
>>> >>floating-point modes with an add/subtract immediate.
>>> >>
>>> >>However, the implentation, as posted, doesn't work - it causes memory
>>> >>corruption.
>>> >>
>>> >>It appears to work with the attached amendment patch.
>>> >>
>> >Indeed,  thanks for pointing out the bad reusing of the aux field
>> >between multiple entities.
>> >
>> >In fact rereading this part of the implementation, I find the allocation
>> >of aux*n_entities awkward. A simpler setting in the entity loop to carry
>> >the mode directly into eg->aux is possible without array allocation
>> >(which also fixes a memory leak by the way).
>> >
> Here is the revised version fixing the aforementioned issue found by
> Joern on Epiphany. It also simplifies the allocation of the aux edges
> field to carry the modes.
>
> Now that everyone agrees on the interface, is this OK for trunk ?
>
> bootstrapped/regtested for X86 and SH4a.
>
> thanks,
>
> Christian
>
>
>
>
>
>
>
> toggle.patch
>
>
> 2014-06-12  Christian Bruel<christian.bruel@st.com>
>
> 	* mode-switching.c (struct bb_info): Add mode_out, mode_in caches.
> 	(make_preds_opaque): Delete.
> 	(clear_mode_bit, mode_bit_p, set_mode_bit): New macros.
> 	(commit_mode_sets): New function.
> 	(optimize_mode_switching): Handle current_mode to mode_switching_emit.
> 	Process all modes at once.
> 	* basic-block.h (pre_edge_lcm_avs): Declare.
> 	* lcm.c (pre_edge_lcm_avs): Renamed from pre_edge_lcm.
> 	Call clear_aux_for_edges. Fix comments.
> 	(pre_edge_lcm): New wrapper function to call pre_edge_lcm_avs.
> 	(pre_edge_rev_lcm): Idem.
> 	* config/epiphany/epiphany.c (emit_set_fp_mode): Add prev_mode parameter.
> 	* config/epiphany/epiphany-protos.h (emit_set_fp_mode): Idem.
> 	* config/epiphany/resolve-sw-modes.c (pass_resolve_sw_modes::execute): Idem.
> 	* config/i386/i386.c (x96_emit_mode_set): Idem.
> 	* config/sh/sh.c (sh_emit_mode_set): Likewise. Handle PR toggle.
> 	* config/sh/sh.md (toggle_pr): 	Defined if TARGET_FPU_SINGLE.
> 	(fpscr_toggle) Disallow from delay slot.
> 	* target.def (emit_mode_set): Add prev_mode parameter.
> 	* doc/tm.texi: Regenerate.
>
> 2014-06-12  Christian Bruel<christian.bruel@st.com>
>
> 	* gcc.target/sh/fpchg.c: New test.
This is fine for the trunk.

Thanks for your patience,
Jeff

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2014-06-17 21:19 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-28  8:12 [PING][PATCH] Extend mode-switching to support toggle (1/2) Christian Bruel
2014-05-12  8:44 ` [PING*2][PATCH] " Christian Bruel
2014-05-12  9:06   ` Christian Bruel
2014-05-12 10:32     ` Kaz Kojima
2014-05-12 22:35       ` Oleg Endo
2014-05-12 11:11     ` Joern Rennecke
2014-05-12 12:16       ` Christian Bruel
2014-05-12 12:51         ` Joern Rennecke
2014-05-12 13:02           ` Joern Rennecke
2014-05-12 22:39           ` Oleg Endo
2014-05-13  8:11             ` Joern Rennecke
2014-05-13 21:41               ` Oleg Endo
2014-06-10 14:03                 ` Joern Rennecke
2014-06-11 12:40                   ` Christian Bruel
2014-06-11 21:16                     ` Oleg Endo
2014-05-26 15:32         ` Christian Bruel
2014-06-02 12:34           ` Christian Bruel
2014-06-11  4:17             ` Joern Rennecke
2014-06-11 12:00               ` Christian Bruel
2014-06-12 14:35                 ` Christian Bruel
2014-06-17 21:19                   ` Jeff Law

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).