summaryrefslogtreecommitdiff
path: root/gcc/mode-switching.c
diff options
context:
space:
mode:
authorchrbr <chrbr@138bc75d-0d04-0410-961f-82ee72b054a4>2014-07-02 13:03:14 +0000
committerchrbr <chrbr@138bc75d-0d04-0410-961f-82ee72b054a4>2014-07-02 13:03:14 +0000
commit7fc0df2f06324a649ce0c5d58251e57b7b948268 (patch)
treed5f4efb38c4b5345b26af85c0f13b1a9412dd461 /gcc/mode-switching.c
parentd57a14220e72765e991e651383bb3fa1e4f4f064 (diff)
downloadgcc-7fc0df2f06324a649ce0c5d58251e57b7b948268.tar.gz
Support mode toggle.
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@212230 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/mode-switching.c')
-rw-r--r--gcc/mode-switching.c334
1 files changed, 197 insertions, 137 deletions
diff --git a/gcc/mode-switching.c b/gcc/mode-switching.c
index c06f113328d..488f2a36489 100644
--- a/gcc/mode-switching.c
+++ b/gcc/mode-switching.c
@@ -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);
-
-/* 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 *info)
}
}
-/* 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, const int *num_modes)
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;
+
+ /* These bitmaps are used for the LCM algorithm. */
+ sbitmap *kill, *del, *insert, *antic, *transp, *comp;
+ sbitmap *avin, *avout;
- for (e = N_ENTITIES - 1, n_entities = 0; e >= 0; e--)
+ 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);
- transp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_entities);
- comp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), n_entities);
+ 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);
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]];
-
- /* 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;
+ edge_list = pre_edge_lcm_avs (n_entities * max_num_modes, transp, comp, antic,
+ kill, avin, avout, &insert, &del);
- eg->aux = 0;
-
- if (! bitmap_bit_p (insert[e], j))
- continue;
-
- eg->aux = (void *)1;
+ for (j = n_entities - 1; j >= 0; j--)
+ {
+ int no_mode = num_modes[entity_map[j]];
- mode = current_mode[j];
- src_bb = eg->src;
+ /* Insert all mode sets that have been inserted by lcm. */
- REG_SET_TO_HARD_REG_SET (live_at_edge, df_get_live_out (src_bb));
+ for (int ed = NUM_EDGES (edge_list) - 1; ed >= 0; ed--)
+ {
+ edge eg = INDEX_EDGE (edge_list, ed);
- 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 ();
+ eg->aux = (void *)(intptr_t)-1;
- /* Do not bother to insert empty sequence. */
- if (mode_set == NULL_RTX)
- continue;
+ 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;
+ }
+ }
+ }
- /* We should not get an abnormal edge here. */
- gcc_assert (! (eg->flags & EDGE_ABNORMAL));
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ struct bb_info *info = bb_info[j];
+ int last_mode = no_mode;
- need_commit = 1;
- insert_insn_on_edge (mode_set, eg);
- }
+ /* 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;
- 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);
- 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]);
+
+ /* Reset modes for next entity. */
+ clear_aux_for_edges ();
- 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 ();