From 7fc0df2f06324a649ce0c5d58251e57b7b948268 Mon Sep 17 00:00:00 2001 From: chrbr Date: Wed, 2 Jul 2014 13:03:14 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 23 +++ gcc/basic-block.h | 3 + gcc/config/epiphany/epiphany-protos.h | 3 +- gcc/config/epiphany/epiphany.c | 3 +- gcc/config/epiphany/resolve-sw-modes.c | 2 +- gcc/config/i386/i386.c | 3 +- gcc/config/sh/sh.c | 14 +- gcc/config/sh/sh.md | 10 +- gcc/doc/tm.texi | 6 +- gcc/lcm.c | 34 +++- gcc/mode-switching.c | 334 +++++++++++++++++++-------------- gcc/target.def | 6 +- gcc/testsuite/ChangeLog | 4 + 13 files changed, 281 insertions(+), 164 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e2ddd54..e60890b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,26 @@ +2014-07-02 Christian Bruel + + * 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 * config/aarch64/aarch64.c (aarch64_expand_vec_perm): Delete unused diff --git a/gcc/basic-block.h b/gcc/basic-block.h index 0bf6e87..f417b34 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 bfa4802..98342a8 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 5a4d89e..a9a3711 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 f65fe2a..a0c4fa4 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 8046c67..d29a25b 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 ac157e4..02468da 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 d998af9..b5d05f4 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 45281ae..9dd8d68 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 2f02129..cf69428 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 c06f113..488f2a3 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 ee250e6..3a41db1 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 ad46526..9bea01c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2014-07-02 Christian Bruel + + * gcc.target/sh/fpchg.c: New test. + 2014-07-02 Jakub Jelinek Fritz Reese -- 2.7.4