and the toggle-support hookized.... many thanks,
Christian
2014-04-02 Christian Bruel <christian.br...@st.com> * target.def (mode_switching): New hook vector. (toggle_init, toggle_destroy, toggle_set, toggle_test): New mode toggle hooks. * targhooks.h (default_toggle_test): Declare. * 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. * mode-switching.c (init_modes_infos): New function. (free_modes_infos): Likewise. (add_mode_set): Likewise. (get_mode): Likewise. (commit_mode_sets): Likewise. (merge_modes): Likewise. (optimize_mode_switching): Support mode toggle. (default_priority_to_mode, default_toggle_test): Define. * doc/tm.texi.in (TARGET_MODE_TOGGLE_INIT, TARGET_MODE_TOGGLE_TEST) (TARGET_MODE_TOGGLE_DESTROY, TARGET_MODE_TOGGLE_SET): New target hooks. * doc/tm.texi: Regenerate. * config/sh/sh.c (sh4_toggle_init, sh4_toggle_destroy): Add hook and define. (sh4_toggle_set, sh4_toggle_test): Likewise. (mode_in_flip, mode_out_flip): Add bitmap to compute mode flipping. (TARGET_MODE_EMIT): New toggle parameter. * 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. * config/i386/i386.c (ix86_emit_mode_set): Add bool unused parameter. * config/epiphany/epiphany.c (emit_set_fp_mode): Add bool unused parameter. --- gcc/basic-block.h 2014-01-07 10:30:59.000000000 +0100 +++ /work1/bruel/superh_elf/gnu_trunk.devs/gcc/gcc/basic-block.h 2014-04-15 16:17:53.000000000 +0200 @@ -711,6 +711,9 @@ 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 **, --- gcc/config/epiphany/epiphany.c 2014-04-17 13:23:48.000000000 +0200 +++ /work1/bruel/superh_elf/gnu_trunk.devs/gcc/gcc/config/epiphany/epiphany.c 2014-04-17 13:25:54.000000000 +0200 @@ -2529,7 +2529,8 @@ } void -emit_set_fp_mode (int entity, int mode, HARD_REG_SET regs_live ATTRIBUTE_UNUSED) +emit_set_fp_mode (int entity, int mode, bool toggle ATTRIBUTE_UNUSED, + HARD_REG_SET regs_live ATTRIBUTE_UNUSED) { rtx save_cc, cc_reg, mask, src, src2; enum attr_fp_mode fp_mode; --- gcc/config/epiphany/epiphany-protos.h 2014-04-17 11:10:36.000000000 +0200 +++ /work1/bruel/superh_elf/gnu_trunk.devs/gcc/gcc/config/epiphany/epiphany-protos.h 2014-04-17 11:22:02.000000000 +0200 @@ -40,7 +40,8 @@ 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, + bool toggle ATTRIBUTE_UNUSED, 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); --- gcc/config/epiphany/resolve-sw-modes.c 2014-04-17 11:10:36.000000000 +0200 +++ /work1/bruel/superh_elf/gnu_trunk.devs/gcc/gcc/config/epiphany/resolve-sw-modes.c 2014-04-17 11:21:07.000000000 +0200 @@ -147,7 +147,7 @@ } start_sequence (); emit_set_fp_mode (EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN, - jilted_mode, NULL); + jilted_mode, false, NULL); seq = get_insns (); end_sequence (); need_commit = true; --- gcc/config/i386/i386.c 2014-04-17 13:02:49.000000000 +0200 +++ /work1/bruel/superh_elf/gnu_trunk.devs/gcc/gcc/config/i386/i386.c 2014-04-17 13:04:18.000000000 +0200 @@ -16409,7 +16409,8 @@ 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, bool toggle ATTRIBUTE_UNUSED, + HARD_REG_SET regs_live) { switch (entity) { --- gcc/config/sh/sh.c 2014-04-17 13:23:07.000000000 +0200 +++ /work1/bruel/superh_elf/gnu_trunk.devs/gcc/gcc/config/sh/sh.c 2014-04-17 13:25:27.000000000 +0200 @@ -202,7 +202,7 @@ 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 sh4_emit_mode_set (int, int, HARD_REG_SET); +static void sh4_emit_mode_set (int, int, bool, HARD_REG_SET); static int sh4_mode_needed (int, rtx); static int sh4_mode_after (int, int, rtx); static int sh4_mode_entry (int); @@ -590,9 +590,21 @@ #undef TARGET_MODE_EXIT #define TARGET_MODE_EXIT sh4_mode_exit +#undef TARGET_MODE_TOGGLE_INIT +#define TARGET_MODE_TOGGLE_INIT sh4_toggle_init + #undef TARGET_MODE_PRIORITY #define TARGET_MODE_PRIORITY sh4_mode_priority +#undef TARGET_MODE_TOGGLE_DESTROY +#define TARGET_MODE_TOGGLE_DESTROY sh4_toggle_destroy + +#undef TARGET_MODE_TOGGLE_SET +#define TARGET_MODE_TOGGLE_SET sh4_toggle_set + +#undef TARGET_MODE_TOGGLE_TEST +#define TARGET_MODE_TOGGLE_TEST sh4_toggle_test + /* Return regmode weight for insn. */ #define INSN_REGMODE_WEIGHT(INSN, MODE)\ regmode_weight[((MODE) == SImode) ? 0 : 1][INSN_UID (INSN)] @@ -13531,20 +13543,26 @@ } static void -sh4_emit_mode_set (int entity ATTRIBUTE_UNUSED, int mode, - HARD_REG_SET regs_live) +sh4_emit_mode_set (int ATTRIBUTE_UNUSED entity, int mode, bool toggle, HARD_REG_SET regs_live) { - fpscr_set_from_mem (mode, regs_live); + if ((TARGET_SH4A_FP || TARGET_SH4_300) && toggle) + { + emit_insn (gen_toggle_pr ()); + if (TARGET_FMOVD) + emit_insn (gen_toggle_sz ()); + } + else + fpscr_set_from_mem (mode, regs_live); } static int -sh4_mode_needed (int entity ATTRIBUTE_UNUSED, rtx insn) +sh4_mode_needed (int ATTRIBUTE_UNUSED entity, rtx insn) { return recog_memoized (insn) >= 0 ? get_attr_fp_mode (insn) : FP_MODE_NONE; } static int -sh4_mode_after (int entity ATTRIBUTE_UNUSED, int mode, rtx insn) +sh4_mode_after (int ATTRIBUTE_UNUSED entity, int mode, rtx insn) { if (TARGET_HITACHI && recog_memoized (insn) >= 0 && get_attr_fp_set (insn) != FP_SET_NONE) @@ -13571,4 +13589,62 @@ return ((TARGET_FPU_SINGLE != 0) ^ (n) ? FP_MODE_SINGLE : FP_MODE_DOUBLE); } +/* 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 +sh4_toggle_test (int entity, int index, bool out) +{ + if (out) + return bitmap_bit_p (mode_out_flip[index], entity); + else + return bitmap_bit_p (mode_in_flip[index], entity); +} + +/* Merges the modes. */ + +static void +sh4_toggle_set (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]); + } +} + +static void +sh4_toggle_init (int n_entities) +{ + 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)); +} + +void +sh4_toggle_destroy (void) +{ + sbitmap_vector_free (mode_in_flip); + sbitmap_vector_free (mode_out_flip); +} + #include "gt-sh.h" --- gcc/config/sh/sh.md 2014-04-14 10:33:21.000000000 +0200 +++ /work1/bruel/superh_elf/gnu_trunk.devs/gcc/gcc/config/sh/sh.md 2014-04-15 16:17:48.000000000 +0200 @@ -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"))) @@ -12196,15 +12197,10 @@ "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")]) --- gcc/doc/tm.texi 2014-04-17 15:17:11.000000000 +0200 +++ /work1/bruel/superh_elf/gnu_trunk.devs/gcc/gcc/doc/tm.texi 2014-04-17 15:09:51.000000000 +0200 @@ -9736,12 +9736,12 @@ 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}, bool @var{toggle}, 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{toggle} is a boolean to indicate that current mode is known an thus can be toggled. 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}) @@ -9760,6 +9760,22 @@ This macro specifies the order in which modes for @var{entity} are processed. 0 is the highest priority, @code{NUM_MODES_FOR_MODE_SWITCHING[@var{entity}] - 1} the lowest. The value of the macro should be an integer designating a mode for @var{entity}. For any fixed @var{entity}, @code{mode_priority} (@var{entity}, @var{n}) shall be a bijection in 0 @dots{} @code{num_modes_for_mode_switching[@var{entity}] - 1}. @end deftypefn +@deftypefn {Target Hook} void TARGET_MODE_TOGGLE_INIT (int @var{n_entity}) +Initializes target-specific data used in maintain toggle information. +@end deftypefn + +@deftypefn {Target Hook} void TARGET_MODE_TOGGLE_DESTROY (void) +Finalizes target-specific data used to maintain toggle information. +@end deftypefn + +@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 + +@deftypefn {Target Hook} bool TARGET_MODE_TOGGLE_TEST (int @var{entity}, int @var{bb}, bool @var{out}) +Hook used by mode switching pass to test if the current @var{entity}'s mode is available for basic block @var{bb} on all incoming edges (@var{out} false) or outgoing edges (@var{out} true). +@end deftypefn + @node Target Attributes @section Defining target-specific uses of @code{__attribute__} @cindex target attributes --- gcc/doc/tm.texi.in 2014-04-17 15:16:54.000000000 +0200 +++ /work1/bruel/superh_elf/gnu_trunk.devs/gcc/gcc/doc/tm.texi.in 2014-04-17 15:09:29.000000000 +0200 @@ -7417,6 +7417,14 @@ @hook TARGET_MODE_PRIORITY +@hook TARGET_MODE_TOGGLE_INIT + +@hook TARGET_MODE_TOGGLE_DESTROY + +@hook TARGET_MODE_TOGGLE_SET + +@hook TARGET_MODE_TOGGLE_TEST + @node Target Attributes @section Defining target-specific uses of @code{__attribute__} @cindex target attributes --- gcc/lcm.c 2014-01-20 10:07:28.000000000 +0100 +++ /work1/bruel/superh_elf/gnu_trunk.devs/gcc/gcc/lcm.c 2014-04-15 16:17:44.000000000 +0200 @@ -377,17 +377,17 @@ } } -/* 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 @@ #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 @@ sbitmap_vector_free (antout); sbitmap_vector_free (antin); - sbitmap_vector_free (avout); later = sbitmap_vector_alloc (num_edges, n_exprs); @@ -485,6 +481,28 @@ 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. */ --- gcc/mode-switching.c 2014-04-17 13:28:18.000000000 +0200 +++ /work1/bruel/superh_elf/gnu_trunk.devs/gcc/gcc/mode-switching.c 2014-04-17 13:28:30.000000000 +0200 @@ -95,6 +95,126 @@ 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; + +/* 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. */ + if (targetm.mode_switching.toggle_init) + targetm.mode_switching.toggle_init (n_entities); +} + +/* frees memory used to hold the modes information. */ + +static void +free_modes_infos (int n_entities) +{ + if (targetm.mode_switching.toggle_destroy) + targetm.mode_switching.toggle_destroy (); + + for (int j = 0; j < n_entities; j++) + free (modes_needed[j]); + + free (modes_needed); +} + +/* 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; + int prev_mode = targetm.mode_switching.toggle_test (j, + src_bb->index, + true); + + 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, + prev_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. INSN may not be a NOTE_INSN_BASIC_BLOCK, unless it is an empty @@ -200,7 +320,7 @@ 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 +575,8 @@ 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]; @@ -468,6 +586,8 @@ bool emitted ATTRIBUTE_UNUSED = false; basic_block post_entry = 0; basic_block pre_exit = 0; + 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)) @@ -500,7 +620,7 @@ /* 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); } df_analyze (); @@ -510,6 +630,8 @@ 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)); @@ -623,6 +745,9 @@ } 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]; @@ -653,8 +778,12 @@ 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); + + /* Merge modes for all entities. */ + if (targetm.mode_switching.toggle_set) + targetm.mode_switching.toggle_set (avin, avout); for (j = n_entities - 1; j >= 0; j--) { @@ -671,10 +800,6 @@ 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; @@ -683,27 +808,8 @@ 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 (); - 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) - 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) @@ -718,7 +824,10 @@ 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. */ @@ -726,9 +835,18 @@ { 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; + bool toggle_p = targetm.mode_switching.toggle_test (j, + bb->index, + false); + for (ptr = bb_info[j][bb->index].seginfo; ptr; ptr = next) { next = ptr->next; @@ -738,9 +856,13 @@ 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, + toggle_p, ptr->regs_live); + + /* modes kill each other inside a basic block. */ + toggle_p = true; + mode_set = get_insns (); end_sequence (); @@ -772,11 +894,16 @@ 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 (); @@ -789,6 +916,13 @@ return 1; } +bool +default_toggle_test (int ATTRIBUTE_UNUSED entity, + int ATTRIBUTE_UNUSED bb, bool ATTRIBUTE_UNUSED out) +{ + return false; +} + #endif /* OPTIMIZE_MODE_SWITCHING */ static bool --- gcc/target.def 2014-04-17 15:04:30.000000000 +0200 +++ /work1/bruel/superh_elf/gnu_trunk.devs/gcc/gcc/target.def 2014-04-17 15:05:19.000000000 +0200 @@ -5352,12 +5352,12 @@ 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{toggle} is a boolean to indicate that current mode is known an thus can be toggled. 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, bool toggle, 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 @@ -5380,6 +5380,27 @@ "This macro specifies the order in which modes for @var{entity} are processed. 0 is the highest priority, @code{NUM_MODES_FOR_MODE_SWITCHING[@var{entity}] - 1} the lowest. The value of the macro should be an integer designating a mode for @var{entity}. For any fixed @var{entity}, @code{mode_priority} (@var{entity}, @var{n}) shall be a bijection in 0 @dots{} @code{num_modes_for_mode_switching[@var{entity}] - 1}.", int, (int entity, int n), NULL) +DEFHOOK +(toggle_init, + "Initializes target-specific data used in maintain toggle information.", + void, (int n_entity), NULL) + +/* Function to delete target-specific cost modeling data. */ +DEFHOOK +(toggle_destroy, + "Finalizes target-specific data used to maintain toggle information.", + void, (void), NULL) + +DEFHOOK +(toggle_set, + "Hook called by the mode switching pass to record the modes needed for each entities in entry and exit of each basic block.", + void, (sbitmap *avin, sbitmap *avout), NULL) + +DEFHOOK +(toggle_test, + "Hook used by mode switching pass to test if the current @var{entity}'s mode is available for basic block @var{bb} on all incoming edges (@var{out} false) or outgoing edges (@var{out} true). ", + bool, (int entity, int bb, bool out), default_toggle_test) + HOOK_VECTOR_END (mode_switching) /* Close the 'struct gcc_target' definition. */ --- gcc/targhooks.h 2014-04-17 13:07:07.000000000 +0200 +++ /work1/bruel/superh_elf/gnu_trunk.devs/gcc/gcc/targhooks.h 2014-04-17 13:06:34.000000000 +0200 @@ -208,3 +208,7 @@ extern tree std_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *); extern bool can_use_doloop_if_innermost (double_int, double_int, unsigned int, bool); + +extern bool default_toggle_test (int, int, bool); +extern void default_toggle_init (void); +extern void default_toggle_destroy (void);