re PR target/65697 (__atomic memory barriers not strong enough for __sync builtins)
[gcc.git] / gcc / sched-ebb.c
index ca0e1441275590a2e38926bd12fb547e989655d7..03767e6c841b90f9940730652dff19f3dff47ef9 100644 (file)
@@ -1,7 +1,5 @@
 /* Instruction scheduling pass.
-   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
-   Free Software Foundation, Inc.
+   Copyright (C) 1992-2015 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com) Enhanced by,
    and currently maintained by, Jim Wilson (wilson@cygnus.com)
 
@@ -31,16 +29,21 @@ along with GCC; see the file COPYING3.  If not see
 #include "hard-reg-set.h"
 #include "regs.h"
 #include "function.h"
+#include "profile.h"
 #include "flags.h"
 #include "insn-config.h"
 #include "insn-attr.h"
 #include "except.h"
 #include "recog.h"
-#include "cfglayout.h"
 #include "params.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "cfgbuild.h"
+#include "predict.h"
+#include "basic-block.h"
 #include "sched-int.h"
 #include "target.h"
-#include "output.h"
 
 \f
 #ifdef INSN_SCHEDULING
@@ -59,19 +62,18 @@ static basic_block last_bb;
 
 /* Implementations of the sched_info functions for region scheduling.  */
 static void init_ready_list (void);
-static void begin_schedule_ready (rtx);
+static void begin_schedule_ready (rtx_insn *);
 static int schedule_more_p (void);
-static const char *ebb_print_insn (const_rtx, int);
-static int rank (rtx, rtx);
-static int ebb_contributes_to_priority (rtx, rtx);
+static const char *ebb_print_insn (const rtx_insn *, int);
+static int rank (rtx_insn *, rtx_insn *);
+static int ebb_contributes_to_priority (rtx_insn *, rtx_insn *);
 static basic_block earliest_block_with_similiar_load (basic_block, rtx);
-static void add_deps_for_risky_insns (rtx, rtx);
-static basic_block schedule_ebb (rtx, rtx);
-static void debug_ebb_dependencies (rtx, rtx);
+static void add_deps_for_risky_insns (rtx_insn *, rtx_insn *);
+static void debug_ebb_dependencies (rtx_insn *, rtx_insn *);
 
-static void ebb_add_remove_insn (rtx, int);
+static void ebb_add_remove_insn (rtx_insn *, int);
 static void ebb_add_block (basic_block, basic_block);
-static basic_block advance_target_bb (basic_block, rtx);
+static basic_block advance_target_bb (basic_block, rtx_insn *);
 static void ebb_fix_recovery_cfg (int, int, int);
 
 /* Allocate memory and store the state of the frontend.  Return the allocated
@@ -103,7 +105,7 @@ schedule_more_p (void)
 
 /* Print dependency information about ebb between HEAD and TAIL.  */
 static void
-debug_ebb_dependencies (rtx head, rtx tail)
+debug_ebb_dependencies (rtx_insn *head, rtx_insn *tail)
 {
   fprintf (sched_dump,
           ";;   --------------- forward dependences: ------------ \n");
@@ -121,9 +123,9 @@ static void
 init_ready_list (void)
 {
   int n = 0;
-  rtx prev_head = current_sched_info->prev_head;
-  rtx next_tail = current_sched_info->next_tail;
-  rtx insn;
+  rtx_insn *prev_head = current_sched_info->prev_head;
+  rtx_insn *next_tail = current_sched_info->next_tail;
+  rtx_insn *insn;
 
   sched_rgn_n_insns = 0;
 
@@ -144,14 +146,14 @@ init_ready_list (void)
 
 /* INSN is being scheduled after LAST.  Update counters.  */
 static void
-begin_schedule_ready (rtx insn ATTRIBUTE_UNUSED)
+begin_schedule_ready (rtx_insn *insn ATTRIBUTE_UNUSED)
 {
   sched_rgn_n_insns++;
 }
 
 /* INSN is being moved to its place in the schedule, after LAST.  */
 static void
-begin_move_insn (rtx insn, rtx last)
+begin_move_insn (rtx_insn *insn, rtx_insn *last)
 {
   if (BLOCK_FOR_INSN (insn) == last_bb
       /* INSN is a jump in the last block, ...  */
@@ -177,9 +179,7 @@ begin_move_insn (rtx insn, rtx last)
                           && BB_END (last_bb) == insn);
 
       {
-       rtx x;
-
-       x = NEXT_INSN (insn);
+       rtx_insn *x = NEXT_INSN (insn);
        if (e)
          gcc_checking_assert (NOTE_P (x) || LABEL_P (x));
        else
@@ -192,8 +192,13 @@ begin_move_insn (rtx insn, rtx last)
          gcc_assert (NOTE_INSN_BASIC_BLOCK_P (BB_END (bb)));
        }
       else
-       /* Create an empty unreachable block after the INSN.  */
-       bb = create_basic_block (NEXT_INSN (insn), NULL_RTX, last_bb);
+       {
+         /* Create an empty unreachable block after the INSN.  */
+         rtx_insn *next = NEXT_INSN (insn);
+         if (next && BARRIER_P (next))
+           next = NEXT_INSN (next);
+         bb = create_basic_block (next, NULL_RTX, last_bb);
+       }
 
       /* split_edge () creates BB before E->DEST.  Keep in mind, that
         this operation extends scheduling region till the end of BB.
@@ -214,7 +219,7 @@ begin_move_insn (rtx insn, rtx last)
    to be formatted so that multiple output lines will line up nicely.  */
 
 static const char *
-ebb_print_insn (const_rtx insn, int aligned ATTRIBUTE_UNUSED)
+ebb_print_insn (const rtx_insn *insn, int aligned ATTRIBUTE_UNUSED)
 {
   static char tmp[80];
 
@@ -232,7 +237,7 @@ ebb_print_insn (const_rtx insn, int aligned ATTRIBUTE_UNUSED)
    is to be preferred.  Zero if they are equally good.  */
 
 static int
-rank (rtx insn1, rtx insn2)
+rank (rtx_insn *insn1, rtx_insn *insn2)
 {
   basic_block bb1 = BLOCK_FOR_INSN (insn1);
   basic_block bb2 = BLOCK_FOR_INSN (insn2);
@@ -251,8 +256,8 @@ rank (rtx insn1, rtx insn2)
    calculations.  */
 
 static int
-ebb_contributes_to_priority (rtx next ATTRIBUTE_UNUSED,
-                             rtx insn ATTRIBUTE_UNUSED)
+ebb_contributes_to_priority (rtx_insn *next ATTRIBUTE_UNUSED,
+                             rtx_insn *insn ATTRIBUTE_UNUSED)
 {
   return 1;
 }
@@ -338,7 +343,7 @@ earliest_block_with_similiar_load (basic_block last_block, rtx load_insn)
 
   FOR_EACH_DEP (load_insn, SD_LIST_BACK, back_sd_it, back_dep)
     {
-      rtx insn1 = DEP_PRO (back_dep);
+      rtx_insn *insn1 = DEP_PRO (back_dep);
 
       if (DEP_TYPE (back_dep) == REG_DEP_TRUE)
        /* Found a DEF-USE dependence (insn1, load_insn).  */
@@ -348,7 +353,7 @@ earliest_block_with_similiar_load (basic_block last_block, rtx load_insn)
 
          FOR_EACH_DEP (insn1, SD_LIST_FORW, fore_sd_it, fore_dep)
            {
-             rtx insn2 = DEP_CON (fore_dep);
+             rtx_insn *insn2 = DEP_CON (fore_dep);
              basic_block insn2_block = BLOCK_FOR_INSN (insn2);
 
              if (DEP_TYPE (fore_dep) == REG_DEP_TRUE)
@@ -381,12 +386,12 @@ earliest_block_with_similiar_load (basic_block last_block, rtx load_insn)
    insns in given ebb.  */
 
 static void
-add_deps_for_risky_insns (rtx head, rtx tail)
+add_deps_for_risky_insns (rtx_insn *head, rtx_insn *tail)
 {
-  rtx insn, prev;
+  rtx_insn *insn, *prev;
   int classification;
-  rtx last_jump = NULL_RTX;
-  rtx next_tail = NEXT_INSN (tail);
+  rtx_insn *last_jump = NULL;
+  rtx_insn *next_tail = NEXT_INSN (tail);
   basic_block last_block = NULL, bb;
 
   for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
@@ -432,32 +437,23 @@ add_deps_for_risky_insns (rtx head, rtx tail)
                 rank.  */
              if (! sched_insns_conditions_mutex_p (insn, prev))
                {
-                 dep_def _dep, *dep = &_dep;
-
-                 init_dep (dep, prev, insn, REG_DEP_ANTI);
-
-                 if (!(current_sched_info->flags & USE_DEPS_LIST))
+                 if ((current_sched_info->flags & DO_SPECULATION)
+                     && (spec_info->mask & BEGIN_CONTROL))
                    {
-                     enum DEPS_ADJUST_RESULT res;
+                     dep_def _dep, *dep = &_dep;
 
-                     res = sd_add_or_update_dep (dep, false);
+                     init_dep (dep, prev, insn, REG_DEP_ANTI);
 
-                     /* We can't change an existing dependency with
-                        DEP_ANTI.  */
-                     gcc_assert (res != DEP_CHANGED);
-                   }
-                 else
-                   {
-                     if ((current_sched_info->flags & DO_SPECULATION)
-                         && (spec_info->mask & BEGIN_CONTROL))
-                       DEP_STATUS (dep) = set_dep_weak (DEP_ANTI, BEGIN_CONTROL,
-                                                        MAX_DEP_WEAK);
+                     if (current_sched_info->flags & USE_DEPS_LIST)
+                       {
+                         DEP_STATUS (dep) = set_dep_weak (DEP_ANTI, BEGIN_CONTROL,
+                                                          MAX_DEP_WEAK);
 
+                       }
                      sd_add_or_update_dep (dep, false);
-
-                     /* Dep_status could have been changed.
-                        No assertion here.  */
                    }
+                 else
+                   add_dependence (insn, prev, REG_DEP_CONTROL);
                }
 
              break;
@@ -476,14 +472,35 @@ add_deps_for_risky_insns (rtx head, rtx tail)
     }
 }
 
-/* Schedule a single extended basic block, defined by the boundaries HEAD
-   and TAIL.  */
+/* Schedule a single extended basic block, defined by the boundaries
+   HEAD and TAIL.
 
-static basic_block
-schedule_ebb (rtx head, rtx tail)
+   We change our expectations about scheduler behaviour depending on
+   whether MODULO_SCHEDULING is true.  If it is, we expect that the
+   caller has already called set_modulo_params and created delay pairs
+   as appropriate.  If the modulo schedule failed, we return
+   NULL_RTX.  */
+
+basic_block
+schedule_ebb (rtx_insn *head, rtx_insn *tail, bool modulo_scheduling)
 {
   basic_block first_bb, target_bb;
   struct deps_desc tmp_deps;
+  bool success;
+
+  /* Blah.  We should fix the rest of the code not to get confused by
+     a note or two.  */
+  while (head != tail)
+    {
+      if (NOTE_P (head) || DEBUG_INSN_P (head))
+       head = NEXT_INSN (head);
+      else if (NOTE_P (tail) || DEBUG_INSN_P (tail))
+       tail = PREV_INSN (tail);
+      else if (LABEL_P (head))
+       head = NEXT_INSN (head);
+      else
+       break;
+    }
 
   first_bb = BLOCK_FOR_INSN (head);
   last_bb = BLOCK_FOR_INSN (tail);
@@ -530,7 +547,9 @@ schedule_ebb (rtx head, rtx tail)
 
   /* Make ready list big enough to hold all the instructions from the ebb.  */
   sched_extend_ready_list (rgn_n_insns);
-  schedule_block (&target_bb);
+  success = schedule_block (&target_bb, NULL);
+  gcc_assert (success || modulo_scheduling);
+
   /* Free ready list.  */
   sched_finish_ready_list ();
 
@@ -538,7 +557,7 @@ schedule_ebb (rtx head, rtx tail)
      so we may made some of them empty.  Can't assert (b == last_bb).  */
 
   /* Sanity check: verify that all region insns were scheduled.  */
-  gcc_assert (sched_rgn_n_insns == rgn_n_insns);
+  gcc_assert (modulo_scheduling || sched_rgn_n_insns == rgn_n_insns);
 
   /* Free dependencies.  */
   sched_free_deps (current_sched_info->head, current_sched_info->tail, true);
@@ -555,29 +574,14 @@ schedule_ebb (rtx head, rtx tail)
       delete_basic_block (last_bb->next_bb);
     }
 
-  return last_bb;
+  return success ? last_bb : NULL;
 }
 
-/* The one entry point in this file.  */
-
+/* Perform initializations before running schedule_ebbs or a single
+   schedule_ebb.  */
 void
-schedule_ebbs (void)
+schedule_ebbs_init (void)
 {
-  basic_block bb;
-  int probability_cutoff;
-  rtx tail;
-
-  if (profile_info && flag_branch_probabilities)
-    probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY_FEEDBACK);
-  else
-    probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY);
-  probability_cutoff = REG_BR_PROB_BASE / 100 * probability_cutoff;
-
-  /* Taking care of this degenerate case makes the rest of
-     this code simpler.  */
-  if (n_basic_blocks == NUM_FIXED_BLOCKS)
-    return;
-
   /* Setup infos.  */
   {
     memcpy (&ebb_common_sched_info, &haifa_common_sched_info,
@@ -599,11 +603,48 @@ schedule_ebbs (void)
   /* Initialize DONT_CALC_DEPS and ebb-{start, end} markers.  */
   bitmap_initialize (&dont_calc_deps, 0);
   bitmap_clear (&dont_calc_deps);
+}
+
+/* Perform cleanups after scheduling using schedules_ebbs or schedule_ebb.  */
+void
+schedule_ebbs_finish (void)
+{
+  bitmap_clear (&dont_calc_deps);
+
+  /* Reposition the prologue and epilogue notes in case we moved the
+     prologue/epilogue insns.  */
+  if (reload_completed)
+    reposition_prologue_and_epilogue_notes ();
+
+  haifa_sched_finish ();
+}
+
+/* The main entry point in this file.  */
+
+void
+schedule_ebbs (void)
+{
+  basic_block bb;
+  int probability_cutoff;
+  rtx_insn *tail;
+
+  /* Taking care of this degenerate case makes the rest of
+     this code simpler.  */
+  if (n_basic_blocks_for_fn (cfun) == NUM_FIXED_BLOCKS)
+    return;
+
+  if (profile_info && flag_branch_probabilities)
+    probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY_FEEDBACK);
+  else
+    probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY);
+  probability_cutoff = REG_BR_PROB_BASE / 100 * probability_cutoff;
+
+  schedule_ebbs_init ();
 
   /* Schedule every region in the subroutine.  */
-  FOR_EACH_BB (bb)
+  FOR_EACH_BB_FN (bb, cfun)
     {
-      rtx head = BB_HEAD (bb);
+      rtx_insn *head = BB_HEAD (bb);
 
       if (bb->flags & BB_DISABLE_SCHEDULE)
        continue;
@@ -612,7 +653,7 @@ schedule_ebbs (void)
        {
          edge e;
          tail = BB_END (bb);
-         if (bb->next_bb == EXIT_BLOCK_PTR
+         if (bb->next_bb == EXIT_BLOCK_PTR_FOR_FN (cfun)
              || LABEL_P (BB_HEAD (bb->next_bb)))
            break;
          e = find_fallthru_edge (bb->succs);
@@ -625,35 +666,14 @@ schedule_ebbs (void)
          bb = bb->next_bb;
        }
 
-      /* Blah.  We should fix the rest of the code not to get confused by
-        a note or two.  */
-      while (head != tail)
-       {
-         if (NOTE_P (head) || DEBUG_INSN_P (head))
-           head = NEXT_INSN (head);
-         else if (NOTE_P (tail) || DEBUG_INSN_P (tail))
-           tail = PREV_INSN (tail);
-         else if (LABEL_P (head))
-           head = NEXT_INSN (head);
-         else
-           break;
-       }
-
-      bb = schedule_ebb (head, tail);
+      bb = schedule_ebb (head, tail, false);
     }
-  bitmap_clear (&dont_calc_deps);
-
-  /* Reposition the prologue and epilogue notes in case we moved the
-     prologue/epilogue insns.  */
-  if (reload_completed)
-    reposition_prologue_and_epilogue_notes ();
-
-  haifa_sched_finish ();
+  schedule_ebbs_finish ();
 }
 
 /* INSN has been added to/removed from current ebb.  */
 static void
-ebb_add_remove_insn (rtx insn ATTRIBUTE_UNUSED, int remove_p)
+ebb_add_remove_insn (rtx_insn *insn ATTRIBUTE_UNUSED, int remove_p)
 {
   if (!remove_p)
     rgn_n_insns++;
@@ -668,7 +688,7 @@ ebb_add_block (basic_block bb, basic_block after)
   /* Recovery blocks are always bounded by BARRIERS,
      therefore, they always form single block EBB,
      therefore, we can use rec->index to identify such EBBs.  */
-  if (after == EXIT_BLOCK_PTR)
+  if (after == EXIT_BLOCK_PTR_FOR_FN (cfun))
     bitmap_set_bit (&dont_calc_deps, bb->index);
   else if (after == last_bb)
     last_bb = bb;
@@ -677,7 +697,7 @@ ebb_add_block (basic_block bb, basic_block after)
 /* Return next block in ebb chain.  For parameter meaning please refer to
    sched-int.h: struct sched_info: advance_target_bb.  */
 static basic_block
-advance_target_bb (basic_block bb, rtx insn)
+advance_target_bb (basic_block bb, rtx_insn *insn)
 {
   if (insn)
     {
@@ -722,7 +742,7 @@ ebb_fix_recovery_cfg (int bbi ATTRIBUTE_UNUSED, int jump_bbi,
   gcc_assert (last_bb->index != bbi);
 
   if (jump_bb_nexti == last_bb->index)
-    last_bb = BASIC_BLOCK (jump_bbi);
+    last_bb = BASIC_BLOCK_FOR_FN (cfun, jump_bbi);
 }
 
 #endif /* INSN_SCHEDULING */