2014-04-02 Christian Bruel <christian.bruel@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.
@@ -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 **,
@@ -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;
@@ -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);
@@ -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;
@@ -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)
{
@@ -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"
@@ -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")])
@@ -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
@@ -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
@@ -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. */
@@ -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
@@ -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. */
@@ -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);