re PR rtl-optimization/61801 (sched2 miscompiles syscall sequence with -g)
[gcc.git] / gcc / sched-deps.c
index 78c5269d6037eb4ab20b0f9115b1e47c3138aa6c..d2715213962d9a5cf70ea453963b5c5a75189a1e 100644 (file)
@@ -1,9 +1,6 @@
 /* Instruction scheduling pass.  This file computes dependencies between
    instructions.
-   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-   2011, 2012
-   Free Software Foundation, Inc.
+   Copyright (C) 1992-2014 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com) Enhanced by,
    and currently maintained by, Jim Wilson (wilson@cygnus.com)
 
@@ -58,7 +55,8 @@ along with GCC; see the file COPYING3.  If not see
 struct sched_deps_info_def *sched_deps_info;
 
 /* The data is specific to the Haifa scheduler.  */
-VEC(haifa_deps_insn_data_def, heap) *h_d_i_d = NULL;
+vec<haifa_deps_insn_data_def>
+    h_d_i_d = vNULL;
 
 /* Return the major type present in the DS.  */
 enum reg_note
@@ -354,6 +352,8 @@ delete_dep_node (dep_node_t n)
   gcc_assert (dep_link_is_detached_p (DEP_NODE_BACK (n))
              && dep_link_is_detached_p (DEP_NODE_FORW (n)));
 
+  XDELETE (DEP_REPLACE (DEP_NODE_DEP (n)));
+
   --dn_pool_diff;
 
   pool_free (dn_pool, n);
@@ -1938,8 +1938,8 @@ create_insn_reg_use (int regno, rtx insn)
   return use;
 }
 
-/* Allocate and return reg_set_data structure for REGNO and INSN.  */
-static struct reg_set_data *
+/* Allocate reg_set_data structure for REGNO and INSN.  */
+static void
 create_insn_reg_set (int regno, rtx insn)
 {
   struct reg_set_data *set;
@@ -1949,7 +1949,6 @@ create_insn_reg_set (int regno, rtx insn)
   set->insn = insn;
   set->next_insn_set = INSN_REG_SET_LIST (insn);
   INSN_REG_SET_LIST (insn) = set;
-  return set;
 }
 
 /* Set up insn register uses for INSN and dependency context DEPS.  */
@@ -2690,8 +2689,15 @@ sched_analyze_2 (struct deps_desc *deps, rtx x, rtx insn)
 
        /* Always add these dependencies to pending_reads, since
           this insn may be followed by a write.  */
-        if (!deps->readonly)
-          add_insn_mem_dependence (deps, true, insn, x);
+       if (!deps->readonly)
+         {
+           if ((deps->pending_read_list_length
+                + deps->pending_write_list_length)
+               > MAX_PENDING_LIST_LENGTH
+               && !DEBUG_INSN_P (insn))
+             flush_pending_lists (deps, insn, true, true);
+           add_insn_mem_dependence (deps, true, insn, x);
+         }
 
        sched_analyze_2 (deps, XEXP (x, 0), insn);
 
@@ -2709,6 +2715,25 @@ sched_analyze_2 (struct deps_desc *deps, rtx x, rtx insn)
     case PREFETCH:
       if (PREFETCH_SCHEDULE_BARRIER_P (x))
        reg_pending_barrier = TRUE_BARRIER;
+      /* Prefetch insn contains addresses only.  So if the prefetch
+        address has no registers, there will be no dependencies on
+        the prefetch insn.  This is wrong with result code
+        correctness point of view as such prefetch can be moved below
+        a jump insn which usually generates MOVE_BARRIER preventing
+        to move insns containing registers or memories through the
+        barrier.  It is also wrong with generated code performance
+        point of view as prefetch withouth dependecies will have a
+        tendency to be issued later instead of earlier.  It is hard
+        to generate accurate dependencies for prefetch insns as
+        prefetch has only the start address but it is better to have
+        something than nothing.  */
+      if (!deps->readonly)
+       {
+         rtx x = gen_rtx_MEM (Pmode, XEXP (PATTERN (insn), 0));
+         if (sched_deps_info->use_cselib)
+           cselib_lookup_from_insn (x, Pmode, true, VOIDmode, insn);
+         add_insn_mem_dependence (deps, true, insn, x);
+       }
       break;
 
     case UNSPEC_VOLATILE:
@@ -2725,7 +2750,8 @@ sched_analyze_2 (struct deps_desc *deps, rtx x, rtx insn)
           Consider for instance a volatile asm that changes the fpu rounding
           mode.  An insn should not be moved across this even if it only uses
           pseudo-regs because it might give an incorrectly rounded result.  */
-       if (code != ASM_OPERANDS || MEM_VOLATILE_P (x))
+       if ((code != ASM_OPERANDS || MEM_VOLATILE_P (x))
+           && !DEBUG_INSN_P (insn))
          reg_pending_barrier = TRUE_BARRIER;
 
        /* For all ASM_OPERANDS, we must traverse the vector of input operands.
@@ -2795,6 +2821,37 @@ sched_analyze_2 (struct deps_desc *deps, rtx x, rtx insn)
     sched_deps_info->finish_rhs ();
 }
 
+/* Try to group comparison and the following conditional jump INSN if
+   they're already adjacent. This is to prevent scheduler from scheduling
+   them apart.  */
+
+static void
+try_group_insn (rtx insn)
+{
+  unsigned int condreg1, condreg2;
+  rtx cc_reg_1;
+  rtx prev;
+
+  if (!any_condjump_p (insn))
+    return;
+
+  targetm.fixed_condition_code_regs (&condreg1, &condreg2);
+  cc_reg_1 = gen_rtx_REG (CCmode, condreg1);
+  prev = prev_nonnote_nondebug_insn (insn);
+  if (!reg_referenced_p (cc_reg_1, PATTERN (insn))
+      || !prev
+      || !modified_in_p (cc_reg_1, prev))
+    return;
+
+  /* Different microarchitectures support macro fusions for different
+     combinations of insn pairs.  */
+  if (!targetm.sched.macro_fusion_pair_p
+      || !targetm.sched.macro_fusion_pair_p (prev, insn))
+    return;
+
+  SCHED_GROUP_P (insn) = 1;
+}
+
 /* Analyze an INSN with pattern X to find all dependencies.  */
 static void
 sched_analyze_insn (struct deps_desc *deps, rtx x, rtx insn)
@@ -2809,7 +2866,7 @@ sched_analyze_insn (struct deps_desc *deps, rtx x, rtx insn)
       HARD_REG_SET temp;
 
       extract_insn (insn);
-      preprocess_constraints ();
+      preprocess_constraints (insn);
       ira_implicitly_set_insn_hard_regs (&temp);
       AND_COMPL_HARD_REG_SET (temp, ira_no_alloc_regs);
       IOR_HARD_REG_SET (implicit_reg_pending_clobbers, temp);
@@ -2818,6 +2875,11 @@ sched_analyze_insn (struct deps_desc *deps, rtx x, rtx insn)
   can_start_lhs_rhs_p = (NONJUMP_INSN_P (insn)
                         && code == SET);
 
+  /* Group compare and branch insns for macro-fusion.  */
+  if (targetm.sched.macro_fusion_p
+      && targetm.sched.macro_fusion_p ())
+    try_group_insn (insn);
+
   if (may_trap_p (x))
     /* Avoid moving trapping instructions across function calls that might
        not always return.  */
@@ -3300,9 +3362,9 @@ sched_analyze_insn (struct deps_desc *deps, rtx x, rtx insn)
             SET_REGNO_REG_SET (&deps->reg_last_in_use, i);
           }
 
-      /* Flush pending lists on jumps, but not on speculative checks.  */
-      if (JUMP_P (insn) && !(sel_sched_p ()
-                             && sel_insn_is_speculation_check (insn)))
+      /* Don't flush pending lists on speculative checks for
+        selective scheduling.  */
+      if (!sel_sched_p () || !sel_insn_is_speculation_check (insn))
        flush_pending_lists (deps, insn, true, true);
 
       reg_pending_barrier = NOT_A_BARRIER;
@@ -3409,6 +3471,15 @@ sched_analyze_insn (struct deps_desc *deps, rtx x, rtx insn)
             change_spec_dep_to_hard (sd_it);
         }
     }
+
+  /* We do not yet have code to adjust REG_ARGS_SIZE, therefore we must
+     honor their original ordering.  */
+  if (find_reg_note (insn, REG_ARGS_SIZE, NULL))
+    {
+      if (deps->last_args_size)
+       add_dependence (insn, deps->last_args_size, REG_DEP_OUTPUT);
+      deps->last_args_size = insn;
+    }
 }
 
 /* Return TRUE if INSN might not always return normally (e.g. call exit,
@@ -3661,12 +3732,6 @@ deps_analyze_insn (struct deps_desc *deps, rtx insn)
   if (sched_deps_info->use_cselib)
     cselib_process_insn (insn);
 
-  /* EH_REGION insn notes can not appear until well after we complete
-     scheduling.  */
-  if (NOTE_P (insn))
-    gcc_assert (NOTE_KIND (insn) != NOTE_INSN_EH_REGION_BEG
-               && NOTE_KIND (insn) != NOTE_INSN_EH_REGION_END);
-
   if (sched_deps_info->finish_insn)
     sched_deps_info->finish_insn ();
 
@@ -3714,6 +3779,10 @@ sched_analyze (struct deps_desc *deps, rtx head, rtx tail)
        {
          /* And initialize deps_lists.  */
          sd_init_insn (insn);
+         /* Clean up SCHED_GROUP_P which may be set by last
+            scheduler pass.  */
+         if (SCHED_GROUP_P (insn))
+           SCHED_GROUP_P (insn) = 0;
        }
 
       deps_analyze_insn (deps, insn);
@@ -3817,6 +3886,7 @@ init_deps (struct deps_desc *deps, bool lazy_reg_last)
   deps->sched_before_next_jump = 0;
   deps->in_post_call_group_p = not_post_call;
   deps->last_debug_insn = 0;
+  deps->last_args_size = 0;
   deps->last_reg_pending_barrier = NOT_A_BARRIER;
   deps->readonly = 0;
 }
@@ -3932,12 +4002,9 @@ remove_from_deps (struct deps_desc *deps, rtx insn)
 static void
 init_deps_data_vector (void)
 {
-  int reserve = (sched_max_luid + 1
-                 - VEC_length (haifa_deps_insn_data_def, h_d_i_d));
-  if (reserve > 0
-      && ! VEC_space (haifa_deps_insn_data_def, h_d_i_d, reserve))
-    VEC_safe_grow_cleared (haifa_deps_insn_data_def, heap, h_d_i_d,
-                           3 * sched_max_luid / 2);
+  int reserve = (sched_max_luid + 1 - h_d_i_d.length ());
+  if (reserve > 0 && ! h_d_i_d.space (reserve))
+    h_d_i_d.safe_grow_cleared (3 * sched_max_luid / 2);
 }
 
 /* If it is profitable to use them, initialize or extend (depending on
@@ -3947,7 +4014,7 @@ sched_deps_init (bool global_p)
 {
   /* Average number of insns in the basic block.
      '+ 1' is used to make it nonzero.  */
-  int insns_in_block = sched_max_luid / n_basic_blocks + 1;
+  int insns_in_block = sched_max_luid / n_basic_blocks_for_fn (cfun) + 1;
 
   init_deps_data_vector ();
 
@@ -4024,7 +4091,7 @@ sched_deps_finish (void)
   free_alloc_pool_if_empty (&dl_pool);
   gcc_assert (dn_pool == NULL && dl_pool == NULL);
 
-  VEC_free (haifa_deps_insn_data_def, heap, h_d_i_d);
+  h_d_i_d.release ();
   cache_size = 0;
 
   if (true_dependency_cache)
@@ -4160,8 +4227,9 @@ add_dependence_1 (rtx insn, rtx elem, enum reg_note dep_type)
     cur_insn = NULL;
 }
 
-/* Return weakness of speculative type TYPE in the dep_status DS.  */
-dw_t
+/* Return weakness of speculative type TYPE in the dep_status DS,
+   without checking to prevent ICEs on malformed input.  */
+static dw_t
 get_dep_weak_1 (ds_t ds, ds_t type)
 {
   ds = ds & type;
@@ -4178,6 +4246,7 @@ get_dep_weak_1 (ds_t ds, ds_t type)
   return (dw_t) ds;
 }
 
+/* Return weakness of speculative type TYPE in the dep_status DS.  */
 dw_t
 get_dep_weak (ds_t ds, ds_t type)
 {
@@ -4555,7 +4624,7 @@ attempt_change (struct mem_inc_info *mii, rtx new_addr)
   rtx mem = *mii->mem_loc;
   rtx new_mem;
 
-  /* Jump thru a lot of hoops to keep the attributes up to date.  We
+  /* Jump through a lot of hoops to keep the attributes up to date.  We
      do not want to call one of the change address variants that take
      an offset even though we know the offset in many cases.  These
      assume you are changing where the address is pointing by the
@@ -4657,7 +4726,7 @@ find_inc (struct mem_inc_info *mii, bool backwards)
       if (parse_add_or_inc (mii, inc_cand, backwards))
        {
          struct dep_replacement *desc;
-         df_ref *def_rec;
+         df_ref def;
          rtx newaddr, newmem;
 
          if (sched_verbose >= 5)
@@ -4666,18 +4735,15 @@ find_inc (struct mem_inc_info *mii, bool backwards)
 
          /* Need to assure that none of the operands of the inc
             instruction are assigned to by the mem insn.  */
-         for (def_rec = DF_INSN_DEFS (mii->mem_insn); *def_rec; def_rec++)
-           {
-             df_ref def = *def_rec;
-             if (reg_overlap_mentioned_p (DF_REF_REG (def), mii->inc_input)
-                 || reg_overlap_mentioned_p (DF_REF_REG (def), mii->mem_reg0))
-               {
-                 if (sched_verbose >= 5)
-                   fprintf (sched_dump,
-                            "inc conflicts with store failure.\n");
-                 goto next;
-               }
-           }
+         FOR_EACH_INSN_DEF (def, mii->mem_insn)
+           if (reg_overlap_mentioned_p (DF_REF_REG (def), mii->inc_input)
+               || reg_overlap_mentioned_p (DF_REF_REG (def), mii->mem_reg0))
+             {
+               if (sched_verbose >= 5)
+                 fprintf (sched_dump,
+                          "inc conflicts with store failure.\n");
+               goto next;
+             }
          newaddr = mii->inc_input;
          if (mii->mem_index != NULL_RTX)
            newaddr = gen_rtx_PLUS (GET_MODE (newaddr), newaddr,
@@ -4752,22 +4818,19 @@ find_mem (struct mem_inc_info *mii, rtx *address_of_x)
        }
       if (REG_P (reg0))
        {
-         df_ref *def_rec;
+         df_ref use;
          int occurrences = 0;
 
          /* Make sure this reg appears only once in this insn.  Can't use
             count_occurrences since that only works for pseudos.  */
-         for (def_rec = DF_INSN_USES (mii->mem_insn); *def_rec; def_rec++)
-           {
-             df_ref def = *def_rec;
-             if (reg_overlap_mentioned_p (reg0, DF_REF_REG (def)))
-               if (++occurrences > 1)
-                 {
-                   if (sched_verbose >= 5)
-                     fprintf (sched_dump, "mem count failure\n");
-                   return false;
-                 }
-           }
+         FOR_EACH_INSN_USE (use, mii->mem_insn)
+           if (reg_overlap_mentioned_p (reg0, DF_REF_REG (use)))
+             if (++occurrences > 1)
+               {
+                 if (sched_verbose >= 5)
+                   fprintf (sched_dump, "mem count failure\n");
+                 return false;
+               }
 
          mii->mem_reg0 = reg0;
          return find_inc (mii, true) || find_inc (mii, false);