From patchwork Fri Apr 4 10:47:11 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Bruel X-Patchwork-Id: 336919 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 02F5114008D for ; Fri, 4 Apr 2014 21:47:43 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:content-type; q=dns; s=default; b=u9XWOpyorzVPJCNSSF9RESNRP7tweDdTQWeiSdIS870 sWfAV2OWJap7FL8yJLCU8U4uKyIq7OX6GL5lHymUrld/ZCaUC+/2bEnHq5Rm8+0w hM+ZjSVpiA3PFkPAsOoZEazuOuoWE/eBsVwxqesFND+RRWzEvQ5v1yAf/RyiVdLs = DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:content-type; s=default; bh=XZOAJG3HEcJ+95goDbblSsZdW84=; b=o10NaJteIjpiVJtpj D9fSXoSUb8ISZJRe3vIQM6+s0R2+xK3bUBoo/3Ur6+udYBy72bn8APuNLLa7I6Ef tYRSfHSwm+JXtjKZuML7uTxApZubq6hdw/ydbvogfKTjASalFF+PkfGYV440I1a2 JoaJCklwcb7HKcE197It6J5xAc= Received: (qmail 30973 invoked by alias); 4 Apr 2014 10:47:36 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 30961 invoked by uid 89); 4 Apr 2014 10:47:36 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.2 required=5.0 tests=AWL, BAYES_40, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 X-HELO: mx07-00178001.pphosted.com Received: from mx07-00178001.pphosted.com (HELO mx07-00178001.pphosted.com) (62.209.51.94) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Fri, 04 Apr 2014 10:47:32 +0000 Received: from pps.filterd (m0046668.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.14.5/8.14.5) with SMTP id s34Ah8GQ017724; Fri, 4 Apr 2014 12:47:28 +0200 Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com with ESMTP id 1jyfcjw9ad-1 (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT); Fri, 04 Apr 2014 12:47:27 +0200 Received: from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id C06FA51; Fri, 4 Apr 2014 10:47:12 +0000 (GMT) Received: from Webmail-eu.st.com (safex1hubcas1.st.com [10.75.90.14]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 55CC32C3FB; Fri, 4 Apr 2014 10:47:12 +0000 (GMT) Received: from [164.129.122.166] (164.129.122.166) by webmail-eu.st.com (10.75.90.13) with Microsoft SMTP Server (TLS) id 8.3.298.1; Fri, 4 Apr 2014 12:47:11 +0200 Message-ID: <533E8DAF.5040405@st.com> Date: Fri, 4 Apr 2014 12:47:11 +0200 From: Christian Bruel User-Agent: Mozilla/5.0 (X11; Linux i686 on x86_64; rv:17.0) Gecko/20130307 Thunderbird/17.0.4 MIME-Version: 1.0 To: "gcc-patches@gcc.gnu.org" Cc: Kaz Kojima Subject: [PATCH] Extend mode-switching to support toggle X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:5.11.87, 1.0.14, 0.0.0000 definitions=2014-04-04_04:2014-04-04, 2014-04-04, 1970-01-01 signatures=0 X-IsSubscribed: yes Respin of a long standing forgotten patch (http://gcc.gnu.org/ml/gcc-patches/2006-12/msg01562.html). This patch extends the mode-switching pass to toggle on/off a control register status bit instead of setting the value. e.g on the SH4a to support the FPCHG instruction used to switch FPU precision mode. The idea is to use the AVOUT/AVIN information computed by LCM for each mode on the CFG edges. When 2 modes for a given entity conflict, a regular mode set is emitted. Elsewhere the same mode is set is for all outgoing/incoming edges, a toggle is possible. The only important general change is that we have to postpone the mode toggling (or setting) after the modes have been computed for each edges. bootstrapped/regtested for x86_64-unknown-linux-gnu and sh-none-elf/sh-linux with for -m4a, and -m4 Comments appreciated. If OK go for trunk/stage1 ? many thanks, 2014-04-02 Christian Bruel * basic-block.h (pre_edge_lcm_avs): Declare. * doc/tm.texi (EMIT_MODE_TOGGLE): Document. * doc/tm.texi.in (EMIT_MODE_TOGGLE): Idem. * config/sh/sh.h (EMIT_MODE_TOGGLE): Define. * config/sh/sh-protos.h (emit_fpu_toggle): Declare * config/sh/sh.c (emit_fpu_toggle): New function. * config/sh/sh.md (toggle_pr): Defined for TARGET_SH4_300 and TARGET_SH4A_FP. (in_delay_slot): fpscr_toggle don't go in delay slot. * 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. * mode-switching.c (init_modes_infos): New function. (free_modes_infos): Idem. (init_modes_infos): Idem (add_mode_set): Idem. (get_mode): Idem. (commit_mode_sets): Idem. (merge_modes): Idem. (set_flip_status): Idem (test_flip_status): Idem. (optimize_mode_switching): Add support to toggle modes. 2014-04-02 Christian Bruel * gcc.target/sh/fpchg1.c: New test. Index: gcc/basic-block.h =================================================================== --- gcc/basic-block.h (revision 208956) +++ 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/sh/sh-protos.h =================================================================== --- gcc/config/sh/sh-protos.h (revision 208956) +++ gcc/config/sh/sh-protos.h (working copy) @@ -210,6 +210,7 @@ extern bool check_use_sfunc_addr (rtx, rtx); #ifdef HARD_CONST extern void fpscr_set_from_mem (int, HARD_REG_SET); #endif +extern bool emit_fpu_toggle (int); extern void sh_pr_interrupt (struct cpp_reader *); extern void sh_pr_trapa (struct cpp_reader *); Index: gcc/config/sh/sh.c =================================================================== --- gcc/config/sh/sh.c (revision 208956) +++ gcc/config/sh/sh.c (working copy) @@ -10042,6 +10042,17 @@ get_free_reg (HARD_REG_SET regs_live) return gen_rtx_REG (Pmode, 7); } +/* This function switches the fpscr. */ +bool +emit_fpu_toggle (int e ATTRIBUTE_UNUSED) +{ + emit_insn (gen_toggle_pr ()); + if (TARGET_FMOVD) + emit_insn (gen_toggle_sz ()); + + return true; +} + /* This function will set the fpscr from memory. MODE is the mode we are setting it to. */ void Index: gcc/config/sh/sh.h =================================================================== --- gcc/config/sh/sh.h (revision 208956) +++ gcc/config/sh/sh.h (working copy) @@ -2259,6 +2259,9 @@ extern int current_function_interrupt; #define MODE_PRIORITY_TO_MODE(ENTITY, N) \ ((TARGET_FPU_SINGLE != 0) ^ (N) ? FP_MODE_SINGLE : FP_MODE_DOUBLE) +#define EMIT_MODE_TOGGLE(ENTITY, MODE) \ + ((TARGET_SH4A_FP || TARGET_SH4_300) ? emit_fpu_toggle (ENTITY) : false) + #define EMIT_MODE_SET(ENTITY, MODE, HARD_REGS_LIVE) \ fpscr_set_from_mem ((MODE), (HARD_REGS_LIVE)) Index: gcc/config/sh/sh.md =================================================================== --- gcc/config/sh/sh.md (revision 208956) +++ 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"))) @@ -12182,15 +12183,10 @@ 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). (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 || TARGET_SH4_300)" "fpchg" [(set_attr "type" "fpscr_toggle")]) Index: gcc/doc/tm.texi =================================================================== --- gcc/doc/tm.texi (revision 208956) +++ gcc/doc/tm.texi (working copy) @@ -9723,6 +9723,11 @@ If you define this macro, you also have to define are optional. @end defmac +@defmac EMIT_MODE_TOGGLE (@var{entity}, @var{mode}) +Generates one or more insns to toggle @var{entity}. Return true if entity supports +toggle. EMIT_MODE_SET is used instead. +@end defmac + @defmac NUM_MODES_FOR_MODE_SWITCHING If you define @code{OPTIMIZE_MODE_SWITCHING}, you have to define this as initializer for an array of integers. Each initializer element Index: gcc/doc/tm.texi.in =================================================================== --- gcc/doc/tm.texi.in (revision 208956) +++ gcc/doc/tm.texi.in (working copy) @@ -7392,6 +7392,11 @@ If you define this macro, you also have to define are optional. @end defmac +@defmac EMIT_MODE_TOGGLE (@var{entity}, @var{mode}) +Generates one or more insns to toggle @var{entity}. Return true if entity supports +toggle. EMIT_MODE_SET is used instead. +@end defmac + @defmac NUM_MODES_FOR_MODE_SWITCHING If you define @code{OPTIMIZE_MODE_SWITCHING}, you have to define this as initializer for an array of integers. Each initializer element Index: gcc/lcm.c =================================================================== --- gcc/lcm.c (revision 208956) +++ 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 208956) +++ gcc/mode-switching.c (working copy) @@ -95,6 +95,178 @@ static void reg_becomes_live (rtx, const_rtx, void static void make_preds_opaque (basic_block, int); +/* To support mode switching, the algorithm cannot set the modes after + the insert and delete bitmaps are computed by pre_edge_lcm, because + 'avin' is computed iteratively for each possible modes for each entity. + The mode emission will be done after all mode are processed. + (see commit_mode_sets). */ + +static int **modes_needed; /* modes needs to be inserted on this edge. */ + +static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING; + +#ifdef EMIT_MODE_TOGGLE + +/* Bitmap to compute mode flipping. */ + +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. */ + +/* Test avin modes. + if 'out' is 1 we want to know if the mode out of the basic block + can be flipped. If 'in' is 1 we want to know if the mode entering the + basic block can be flipped. + If result is 0, we need to reset the mode. */ + +static bool +test_flip_status(int entity, basic_block bb, bool out) +{ + if (out) + return bitmap_bit_p (mode_out_flip[bb->index], entity); + else + return bitmap_bit_p (mode_in_flip[bb->index], entity); +} + +/* Merges the avin modes. */ + +static void +set_flip_status (sbitmap *avin, sbitmap *avout) +{ + basic_block bb; + + FOR_EACH_BB_FN (bb, cfun) + { + int i = bb->index; + + /* Merge modes for each entity for each bb. + If multiple avin modes are set for the same bb, they are not + exclusive and a flip may not be emitted. */ + if (! bb_has_eh_pred (bb)) + bitmap_xor (mode_in_flip[i], mode_in_flip[i], avin[i]); + bitmap_xor (mode_out_flip[i], mode_out_flip[i], avout[i]); + } +} +#endif /* EMIT_MODE_TOGGLE */ + +/* Allocates and initializes modes_infos. */ + +static void +init_modes_infos (int n_entities, int *entity_map) +{ + int num_edges = 0; + basic_block bb; + + FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), + EXIT_BLOCK_PTR_FOR_FN (cfun), next_bb) + num_edges += EDGE_COUNT (bb->succs); + + modes_needed = XNEWVEC (int *, n_entities); + + for (int j = 0; j < n_entities; j++) + { + int e = entity_map[j]; + int no_mode = num_modes[e]; + + modes_needed[j] = XNEWVEC (int, num_edges); + for (int ed = 0; ed < num_edges; ed++) + modes_needed[j][ed] = no_mode; + } + + /* Allocates bitmaps for modes. */ +#ifdef EMIT_MODE_TOGGLE + mode_in_flip = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), + n_entities); + mode_out_flip = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), + n_entities); + bitmap_vector_clear (mode_in_flip, last_basic_block_for_fn (cfun)); + bitmap_vector_clear (mode_out_flip, last_basic_block_for_fn (cfun)); +#endif +} + +/* frees memory used to hold the modes information. */ + +static void +free_modes_infos (int n_entities) +{ + int j; + + for (j = 0; j < n_entities; j++) + free (modes_needed[j]); + + free (modes_needed); +#ifdef EMIT_MODE_TOGGLE + sbitmap_vector_free (mode_in_flip); + sbitmap_vector_free (mode_out_flip); +#endif +} + +/* records the mode associated with edge e for entity j. */ + +static void +add_mode_set (int j, int e, int mode) +{ + modes_needed[j][e] = mode; +} + +/* returns the mode needed on edge e for entity j. -1 if none. */ + +static int +get_mode (int j, int e) +{ + return modes_needed[j][e]; +} + +/* Finally, after all the modes after been inserted after lcm, we can + process with the mode emission. */ + +static bool +commit_mode_sets (struct edge_list *edge_list, int j, int *entity_map) +{ + bool need_commit = false; + + for (int ed = NUM_EDGES (edge_list) - 1; ed >= 0; ed--) + { + int mode; + int e = entity_map[j]; + int no_mode = num_modes[e]; + + if ((mode = get_mode (j, ed)) != no_mode) + { + HARD_REG_SET live_at_edge; + edge eg = INDEX_EDGE (edge_list, ed); + basic_block src_bb = eg->src; + 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 (); + +#ifdef EMIT_MODE_TOGGLE + if (! test_flip_status (j, src_bb, true) || + ! EMIT_MODE_TOGGLE (entity_map[j], mode)) +#endif + EMIT_MODE_SET (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) + 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; +} + /* This function will allocate a new BBINFO structure, initialized with the MODE, INSN, and basic block BB parameters. */ @@ -201,7 +373,7 @@ reg_becomes_live (rtx reg, const_rtx setter ATTRIB inserted before the exit block. Otherwise return null. */ static basic_block -create_pre_exit (int n_entities, int *entity_map, const int *num_modes) +create_pre_exit (int n_entities, int *entity_map) { edge eg; edge_iterator ei; @@ -455,10 +627,8 @@ optimize_mode_switching (void) rtx insn; int e; basic_block bb; - int need_commit = 0; + bool need_commit = false; sbitmap *kill; - struct edge_list *edge_list; - static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING; #define N_ENTITIES ARRAY_SIZE (num_modes) int entity_map[N_ENTITIES]; struct bb_info *bb_info[N_ENTITIES]; @@ -467,6 +637,8 @@ optimize_mode_switching (void) int max_num_modes = 0; bool emitted ATTRIBUTE_UNUSED = false; basic_block post_entry ATTRIBUTE_UNUSED, pre_exit ATTRIBUTE_UNUSED; + sbitmap *avin, *avout; + struct edge_list *edge_list = 0; for (e = N_ENTITIES - 1, n_entities = 0; e >= 0; e--) if (OPTIMIZE_MODE_SWITCHING (e)) @@ -494,7 +666,7 @@ optimize_mode_switching (void) /* Split the edge from the entry block, so that we can note that there NORMAL_MODE is supplied. */ post_entry = split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun))); - pre_exit = create_pre_exit (n_entities, entity_map, num_modes); + pre_exit = create_pre_exit (n_entities, entity_map); #endif df_analyze (); @@ -504,6 +676,8 @@ optimize_mode_switching (void) 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); + avin = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_entities); + avout = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_entities); bitmap_vector_ones (transp, last_basic_block_for_fn (cfun)); @@ -610,6 +784,9 @@ optimize_mode_switching (void) } kill = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_entities); + + init_modes_infos (n_entities, entity_map); + for (i = 0; i < max_num_modes; i++) { int current_mode[N_ENTITIES]; @@ -639,9 +816,14 @@ optimize_mode_switching (void) 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); + edge_list = pre_edge_lcm_avs (n_entities, transp, comp, antic, + kill, avin, avout, &insert, &del); +#ifdef EMIT_MODE_TOGGLE + /* Merge modes for all entities. */ + set_flip_status (avin, avout); +#endif + for (j = n_entities - 1; j >= 0; j--) { /* Insert all mode sets that have been inserted by lcm. */ @@ -657,10 +839,6 @@ optimize_mode_switching (void) 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; eg->aux = 0; @@ -669,27 +847,8 @@ optimize_mode_switching (void) eg->aux = (void *)1; - 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 (); - EMIT_MODE_SET (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) - 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. */ + add_mode_set(j, e, current_mode[j]); } FOR_EACH_BB_REVERSE_FN (bb, cfun) @@ -704,7 +863,10 @@ optimize_mode_switching (void) sbitmap_vector_free (del); sbitmap_vector_free (insert); clear_aux_for_edges (); - free_edge_list (edge_list); + + /* Keep an edge_list for later. */ + if (i != max_num_modes - 1) + free_edge_list (edge_list); } /* Now output the remaining mode sets in all the segments. */ @@ -712,9 +874,18 @@ optimize_mode_switching (void) { 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, j, entity_map); + FOR_EACH_BB_REVERSE_FN (bb, cfun) { struct seginfo *ptr, *next; +#ifdef EMIT_MODE_TOGGLE + bool toggle_p = test_flip_status (j, bb, false); +#endif + for (ptr = bb_info[j][bb->index].seginfo; ptr; ptr = next) { next = ptr->next; @@ -724,7 +895,17 @@ optimize_mode_switching (void) rtl_profile_for_bb (bb); start_sequence (); + +#ifdef EMIT_MODE_TOGGLE + if (! toggle_p || + ! EMIT_MODE_TOGGLE (entity_map[j], ptr->mode)) +#endif EMIT_MODE_SET (entity_map[j], ptr->mode, ptr->regs_live); + +#ifdef EMIT_MODE_TOGGLE + toggle_p = true; +#endif + mode_set = get_insns (); end_sequence (); @@ -748,11 +929,16 @@ optimize_mode_switching (void) free (bb_info[j]); } + free_edge_list (edge_list); + free_modes_infos (n_entities); + /* Finished. Free up all the things we've allocated. */ sbitmap_vector_free (kill); sbitmap_vector_free (antic); sbitmap_vector_free (transp); sbitmap_vector_free (comp); + sbitmap_vector_free (avin); + sbitmap_vector_free (avout); if (need_commit) commit_edge_insertions (); Index: gcc/testsuite/gcc.target/sh/fpchg1.c =================================================================== --- gcc/testsuite/gcc.target/sh/fpchg1.c (revision 0) +++ gcc/testsuite/gcc.target/sh/fpchg1.c (working copy) @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O1" } */ +/* { dg-skip-if "" { "sh*-*-*" } { "" } { "-m4a" "-m4-300" } } + +/* Make sure that fpchg is used. */ +/* { dg-final { scan-assembler "fpchg" } } */ +/* { dg-final { scan-assembler-not "fpscr" } } */ + +extern float c; + +void +foo(int j) +{ + while (j--) + c++; + +}