summaryrefslogtreecommitdiff
path: root/gcc
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
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')
-rw-r--r--gcc/ChangeLog23
-rw-r--r--gcc/basic-block.h3
-rw-r--r--gcc/config/epiphany/epiphany-protos.h3
-rw-r--r--gcc/config/epiphany/epiphany.c3
-rw-r--r--gcc/config/epiphany/resolve-sw-modes.c2
-rw-r--r--gcc/config/i386/i386.c3
-rw-r--r--gcc/config/sh/sh.c14
-rw-r--r--gcc/config/sh/sh.md10
-rw-r--r--gcc/doc/tm.texi6
-rw-r--r--gcc/lcm.c34
-rw-r--r--gcc/mode-switching.c334
-rw-r--r--gcc/target.def6
-rw-r--r--gcc/testsuite/ChangeLog4
13 files changed, 281 insertions, 164 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e2ddd54bdd0..e60890bd270 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,26 @@
+2014-07-02 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-07-02 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
* config/aarch64/aarch64.c (aarch64_expand_vec_perm): Delete unused
diff --git a/gcc/basic-block.h b/gcc/basic-block.h
index 0bf6e877145..f417b34a873 100644
--- a/gcc/basic-block.h
+++ b/gcc/basic-block.h
@@ -711,6 +711,9 @@ extern void bitmap_union_of_preds (sbitmap, sbitmap *, basic_block);
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 **,
diff --git a/gcc/config/epiphany/epiphany-protos.h b/gcc/config/epiphany/epiphany-protos.h
index bfa48021443..98342a8d499 100644
--- a/gcc/config/epiphany/epiphany-protos.h
+++ b/gcc/config/epiphany/epiphany-protos.h
@@ -40,7 +40,8 @@ extern int epiphany_initial_elimination_offset (int, int);
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);
diff --git a/gcc/config/epiphany/epiphany.c b/gcc/config/epiphany/epiphany.c
index 5a4d89e4ebc..a9a37115096 100644
--- a/gcc/config/epiphany/epiphany.c
+++ b/gcc/config/epiphany/epiphany.c
@@ -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;
diff --git a/gcc/config/epiphany/resolve-sw-modes.c b/gcc/config/epiphany/resolve-sw-modes.c
index f65fe2a635e..a0c4fa44a41 100644
--- a/gcc/config/epiphany/resolve-sw-modes.c
+++ b/gcc/config/epiphany/resolve-sw-modes.c
@@ -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;
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 8046c67c555..d29a25b13cb 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -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)
{
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index ac157e48c73..02468dadcdd 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -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);
@@ -13583,9 +13583,17 @@ sh_try_omit_signzero_extend (rtx extended_op, rtx insn)
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
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index d998af96ec8..b5d05f4c7de 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -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")])
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 45281aef88a..9dd8d68ddb9 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -9595,12 +9595,12 @@ represented as numbers 0 @dots{} N @minus{} 1. N is used to specify that no mod
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})
diff --git a/gcc/lcm.c b/gcc/lcm.c
index 2f02129aaeb..cf69428a51c 100644
--- a/gcc/lcm.c
+++ b/gcc/lcm.c
@@ -377,17 +377,17 @@ compute_insert_delete (struct edge_list *edge_list, sbitmap *antloc,
}
}
-/* 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 @@ pre_edge_lcm (int n_exprs, sbitmap *transp,
#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 @@ pre_edge_lcm (int n_exprs, sbitmap *transp,
sbitmap_vector_free (antout);
sbitmap_vector_free (antin);
- sbitmap_vector_free (avout);
later = sbitmap_vector_alloc (num_edges, n_exprs);
@@ -485,6 +481,28 @@ pre_edge_lcm (int n_exprs, sbitmap *transp,
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. */
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 ();
diff --git a/gcc/target.def b/gcc/target.def
index ee250e6adfe..3a41db1a6df 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -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
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index ad46526bad6..9bea01cd91f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2014-07-02 Christian Bruel <christian.bruel@st.com>
+
+ * gcc.target/sh/fpchg.c: New test.
+
2014-07-02 Jakub Jelinek <jakub@redhat.com>
Fritz Reese <Reese-Fritz@zai.com>