]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Support mode toggle.
authorChristian Bruel <christian.bruel@st.com>
Wed, 2 Jul 2014 13:03:14 +0000 (15:03 +0200)
committerChristian Bruel <chrbr@gcc.gnu.org>
Wed, 2 Jul 2014 13:03:14 +0000 (15:03 +0200)
* 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.

From-SVN: r212230

13 files changed:
gcc/ChangeLog
gcc/basic-block.h
gcc/config/epiphany/epiphany-protos.h
gcc/config/epiphany/epiphany.c
gcc/config/epiphany/resolve-sw-modes.c
gcc/config/i386/i386.c
gcc/config/sh/sh.c
gcc/config/sh/sh.md
gcc/doc/tm.texi
gcc/lcm.c
gcc/mode-switching.c
gcc/target.def
gcc/testsuite/ChangeLog

index e2ddd54bdd09d054c59d4e5b1ab878127eacc89c..e60890bd2708dc33b5899b81feda605b05bf56e6 100644 (file)
@@ -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
index 0bf6e8771456eaa14493a5b81ef6e982a10de624..f417b34a873704adce16392604ef88421a4f97ad 100644 (file)
@@ -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 **,
index bfa4802144308ffd1f5525231d77fd1e6e0ef26c..98342a8d4998eba404f724c79d379d021846a98d 100644 (file)
@@ -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);
index 5a4d89e4ebc9b780e45a0cb3aec06e3201d31460..a9a3711509698a1efc7ab3f893bbb48343eb0454 100644 (file)
@@ -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;
index f65fe2a635edd2875fa356d66a2dc36334a1521a..a0c4fa44a41395fb81a0a1807a85c6ca626fd99f 100644 (file)
@@ -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;
index 8046c67c5555f2608b71320b12d5099cb1ca723e..d29a25b13cbd8b5632d7dea0c3809087f2598aa5 100644 (file)
@@ -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)
     {
index ac157e48c73196da70222d35f00fd744e3c953bd..02468dadcddbaa6e7d705ba74c1a972864235912 100644 (file)
@@ -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
index d998af96ec831ddaf89a59d79de93707e1ba4b74..b5d05f4c7de00c4b5d1ce1807750b6ecb2fb0f4f 100644 (file)
 (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")])
 
index 45281aef88ad9ad529e31e8396a404d06489e226..9dd8d68ddb9d762607a7aef6f17d49c0b7bc8266 100644 (file)
@@ -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})
index 2f02129aaeb187220ad11f2c0aedbaae700058a4..cf69428a51c4736228c6d7b8191969f4f3428629 100644 (file)
--- 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.  */
 
index c06f113328da35242339de64c2ef8c97099d2d66..488f2a36489b034a277c722292dfcd2f71259f81 100644 (file)
@@ -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);
-\f
 
-/* 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 ();
index ee250e6adfebe75234877fe935be4707dd61197c..3a41db1a6df2bee0e3c918e640a7c05d525d25cb 100644 (file)
@@ -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
index ad46526bad68b5beacce2aab21976a3d97fdc9e2..9bea01cd91f2d41f906e16d669e8e4ab871620f2 100644 (file)
@@ -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>