OSDN Git Service

PR c++/60046
[pf3gnuchains/gcc-fork.git] / gcc / sel-sched.c
index be56ded..43e0d51 100644 (file)
@@ -45,6 +45,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "rtlhooks-def.h"
 #include "output.h"
 #include "emit-rtl.h"
+#include "ira.h"
 
 #ifdef INSN_SCHEDULING
 #include "sel-sched-ir.h"
@@ -794,8 +795,8 @@ substitute_reg_in_expr (expr_t expr, insn_t insn, bool undo)
          /* Do not allow clobbering the address register of speculative
              insns.  */
          if ((EXPR_SPEC_DONE_DS (expr) & SPECULATIVE)
-              && bitmap_bit_p (VINSN_REG_USES (EXPR_VINSN (expr)),
-                              expr_dest_regno (expr)))
+              && register_unavailable_p (VINSN_REG_USES (EXPR_VINSN (expr)),
+                                        expr_dest_reg (expr)))
            EXPR_TARGET_AVAILABLE (expr) = false;
 
          return true;
@@ -813,18 +814,12 @@ count_occurrences_1 (rtx *cur_rtx, void *arg)
 {
   rtx_search_arg_p p = (rtx_search_arg_p) arg;
 
-  /* The last param FOR_GCSE is true, because otherwise it performs excessive
-    substitutions like
-       r8 = r33
-       r16 = r33
-    for the last insn it presumes r33 equivalent to r8, so it changes it to
-    r33.  Actually, there's no change, but it spoils debugging.  */
-  if (exp_equiv_p (*cur_rtx, p->x, 0, true))
-    {
-      /* Bail out if we occupy more than one register.  */
-      if (REG_P (*cur_rtx)
-          && HARD_REGISTER_P (*cur_rtx)
-          && hard_regno_nregs[REGNO(*cur_rtx)][GET_MODE (*cur_rtx)] > 1)
+  if (REG_P (*cur_rtx) && REGNO (*cur_rtx) == REGNO (p->x))
+    {
+      /* Bail out if mode is different or more than one register is used.  */
+      if (GET_MODE (*cur_rtx) != GET_MODE (p->x)
+          || (HARD_REGISTER_P (*cur_rtx)
+             && hard_regno_nregs[REGNO(*cur_rtx)][GET_MODE (*cur_rtx)] > 1))
         {
           p->n = 0;
           return 1;
@@ -837,7 +832,6 @@ count_occurrences_1 (rtx *cur_rtx, void *arg)
     }
 
   if (GET_CODE (*cur_rtx) == SUBREG
-      && REG_P (p->x)
       && (!REG_P (SUBREG_REG (*cur_rtx))
          || REGNO (SUBREG_REG (*cur_rtx)) == REGNO (p->x)))
     {
@@ -859,6 +853,7 @@ count_occurrences_equiv (rtx what, rtx where)
 {
   struct rtx_search_arg arg;
 
+  gcc_assert (REG_P (what));
   arg.x = what;
   arg.n = 0;
 
@@ -1268,7 +1263,7 @@ mark_unavailable_hard_regs (def_t def, struct reg_rename *reg_rename_p,
 
       if (!HARD_FRAME_POINTER_IS_FRAME_POINTER)
         add_to_hard_reg_set (&reg_rename_p->unavailable_hard_regs, 
-                            Pmode, HARD_FRAME_POINTER_IS_FRAME_POINTER);
+                            Pmode, HARD_FRAME_POINTER_REGNUM);
     }
 
 #ifdef STACK_REGS
@@ -1581,7 +1576,7 @@ verify_target_availability (expr_t expr, regset used_regs,
   regno = expr_dest_regno (expr);
   mode = GET_MODE (EXPR_LHS (expr));
   target_available = EXPR_TARGET_AVAILABLE (expr) == 1;
-  n = reload_completed ? hard_regno_nregs[regno][mode] : 1;
+  n = HARD_REGISTER_NUM_P (regno) ? hard_regno_nregs[regno][mode] : 1;
 
   live_available = hard_available = true;
   for (i = 0; i < n; i++)
@@ -2119,6 +2114,61 @@ moving_insn_creates_bookkeeping_block_p (insn_t insn,
   return TRUE;
 }
 
+/* Return true when the conflict with newly created implicit clobbers
+   between EXPR and THROUGH_INSN is found because of renaming.  */
+static bool
+implicit_clobber_conflict_p (insn_t through_insn, expr_t expr)
+{
+  HARD_REG_SET temp;
+  rtx insn, reg, rhs, pat;
+  hard_reg_set_iterator hrsi;
+  unsigned regno;
+  bool valid;
+
+  /* Make a new pseudo register.  */
+  reg = gen_reg_rtx (GET_MODE (EXPR_LHS (expr)));
+  max_regno = max_reg_num ();
+  maybe_extend_reg_info_p ();
+
+  /* Validate a change and bail out early.  */
+  insn = EXPR_INSN_RTX (expr);
+  validate_change (insn, &SET_DEST (PATTERN (insn)), reg, true);
+  valid = verify_changes (0);
+  cancel_changes (0);
+  if (!valid)
+    {
+      if (sched_verbose >= 6)
+       sel_print ("implicit clobbers failed validation, ");
+      return true;
+    }
+
+  /* Make a new insn with it.  */
+  rhs = copy_rtx (VINSN_RHS (EXPR_VINSN (expr)));
+  pat = gen_rtx_SET (VOIDmode, reg, rhs);
+  start_sequence ();
+  insn = emit_insn (pat);
+  end_sequence ();
+
+  /* Calculate implicit clobbers.  */
+  extract_insn (insn);
+  preprocess_constraints ();
+  ira_implicitly_set_insn_hard_regs (&temp);
+  AND_COMPL_HARD_REG_SET (temp, ira_no_alloc_regs);
+
+  /* If any implicit clobber registers intersect with regular ones in
+     through_insn, we have a dependency and thus bail out.  */
+  EXECUTE_IF_SET_IN_HARD_REG_SET (temp, 0, regno, hrsi)
+    {
+      vinsn_t vi = INSN_VINSN (through_insn);
+      if (bitmap_bit_p (VINSN_REG_SETS (vi), regno)
+         || bitmap_bit_p (VINSN_REG_CLOBBERS (vi), regno)
+         || bitmap_bit_p (VINSN_REG_USES (vi), regno))
+       return true;
+    }
+
+  return false;
+}
+
 /* Modifies EXPR so it can be moved through the THROUGH_INSN,
    performing necessary transformations.  Record the type of transformation
    made in PTRANS_TYPE, when it is not NULL.  When INSIDE_INSN_GROUP,
@@ -2251,6 +2301,17 @@ moveup_expr (expr_t expr, insn_t through_insn, bool inside_insn_group,
       if (!enable_schedule_as_rhs_p || !EXPR_SEPARABLE_P (expr))
         return MOVEUP_EXPR_NULL;
 
+      /* When renaming a hard register to a pseudo before reload, extra
+        dependencies can occur from the implicit clobbers of the insn.
+        Filter out such cases here.  */
+      if (!reload_completed && REG_P (EXPR_LHS (expr))
+         && HARD_REGISTER_P (EXPR_LHS (expr))
+         && implicit_clobber_conflict_p (through_insn, expr))
+       {
+         if (sched_verbose >= 6)
+           sel_print ("implicit clobbers conflict detected, ");
+         return MOVEUP_EXPR_NULL;
+       }
       EXPR_TARGET_AVAILABLE (expr) = false;
       was_target_conflict = true;
       as_rhs = true;
@@ -3573,29 +3634,41 @@ process_use_exprs (av_set_t *av_ptr)
   return NULL;
 }
 
-/* Lookup EXPR in VINSN_VEC and return TRUE if found.  */
+/* Lookup EXPR in VINSN_VEC and return TRUE if found.  Also check patterns from
+   EXPR's history of changes.  */
 static bool
 vinsn_vec_has_expr_p (vinsn_vec_t vinsn_vec, expr_t expr)
 {
-  vinsn_t vinsn;
+  vinsn_t vinsn, expr_vinsn;
   int n;
+  unsigned i;
 
-  FOR_EACH_VEC_ELT (vinsn_t, vinsn_vec, n, vinsn)
-    if (VINSN_SEPARABLE_P (vinsn))
-      {
-        if (vinsn_equal_p (vinsn, EXPR_VINSN (expr)))
-          return true;
-      }
-    else
-      {
-        /* For non-separable instructions, the blocking insn can have
-           another pattern due to substitution, and we can't choose
-           different register as in the above case.  Check all registers
-           being written instead.  */
-        if (bitmap_intersect_p (VINSN_REG_SETS (vinsn),
-                                VINSN_REG_SETS (EXPR_VINSN (expr))))
-          return true;
-      }
+  /* Start with checking expr itself and then proceed with all the old forms
+     of expr taken from its history vector.  */
+  for (i = 0, expr_vinsn = EXPR_VINSN (expr);
+       expr_vinsn;
+       expr_vinsn = (i < VEC_length (expr_history_def,
+                                    EXPR_HISTORY_OF_CHANGES (expr))
+                    ? VEC_index (expr_history_def,
+                                 EXPR_HISTORY_OF_CHANGES (expr),
+                                 i++)->old_expr_vinsn
+                    : NULL))
+    FOR_EACH_VEC_ELT (vinsn_t, vinsn_vec, n, vinsn)
+      if (VINSN_SEPARABLE_P (vinsn))
+       {
+         if (vinsn_equal_p (vinsn, expr_vinsn))
+           return true;
+       }
+      else
+       {
+         /* For non-separable instructions, the blocking insn can have
+            another pattern due to substitution, and we can't choose
+            different register as in the above case.  Check all registers
+            being written instead.  */
+         if (bitmap_intersect_p (VINSN_REG_SETS (vinsn),
+                                 VINSN_REG_SETS (expr_vinsn)))
+           return true;
+       }
 
   return false;
 }
@@ -3631,12 +3704,12 @@ av_set_could_be_blocked_by_bookkeeping_p (av_set_t orig_ops, void *static_params
      renaming.  Check with the right register instead.  */
   if (sparams->dest && REG_P (sparams->dest))
     {
-      unsigned regno = REGNO (sparams->dest);
+      rtx reg = sparams->dest;
       vinsn_t failed_vinsn = INSN_VINSN (sparams->failed_insn);
 
-      if (bitmap_bit_p (VINSN_REG_SETS (failed_vinsn), regno)
-         || bitmap_bit_p (VINSN_REG_USES (failed_vinsn), regno)
-         || bitmap_bit_p (VINSN_REG_CLOBBERS (failed_vinsn), regno))
+      if (register_unavailable_p (VINSN_REG_SETS (failed_vinsn), reg)
+         || register_unavailable_p (VINSN_REG_USES (failed_vinsn), reg)
+         || register_unavailable_p (VINSN_REG_CLOBBERS (failed_vinsn), reg))
        return true;
     }
 
@@ -4663,9 +4736,10 @@ create_block_for_bookkeeping (edge e1, edge e2)
 }
 
 /* Return insn after which we must insert bookkeeping code for path(s) incoming
-   into E2->dest, except from E1->src.  */
+   into E2->dest, except from E1->src.  If the returned insn immediately
+   precedes a fence, assign that fence to *FENCE_TO_REWIND.  */
 static insn_t
-find_place_for_bookkeeping (edge e1, edge e2)
+find_place_for_bookkeeping (edge e1, edge e2, fence_t *fence_to_rewind)
 {
   insn_t place_to_insert;
   /* Find a basic block that can hold bookkeeping.  If it can be found, do not
@@ -4707,9 +4781,14 @@ find_place_for_bookkeeping (edge e1, edge e2)
        sel_print ("Pre-existing bookkeeping block is %i\n", book_block->index);
     }
 
-  /* If basic block ends with a jump, insert bookkeeping code right before it.  */
+  *fence_to_rewind = NULL;
+  /* If basic block ends with a jump, insert bookkeeping code right before it.
+     Notice if we are crossing a fence when taking PREV_INSN.  */
   if (INSN_P (place_to_insert) && control_flow_insn_p (place_to_insert))
-    place_to_insert = PREV_INSN (place_to_insert);
+    {
+      *fence_to_rewind = flist_lookup (fences, place_to_insert);
+      place_to_insert = PREV_INSN (place_to_insert);
+    }
 
   return place_to_insert;
 }
@@ -4784,21 +4863,23 @@ generate_bookkeeping_insn (expr_t c_expr, edge e1, edge e2)
   insn_t join_point, place_to_insert, new_insn;
   int new_seqno;
   bool need_to_exchange_data_sets;
+  fence_t fence_to_rewind;
 
   if (sched_verbose >= 4)
     sel_print ("Generating bookkeeping insn (%d->%d)\n", e1->src->index,
               e2->dest->index);
 
   join_point = sel_bb_head (e2->dest);
-  place_to_insert = find_place_for_bookkeeping (e1, e2);
-  if (!place_to_insert)
-    return NULL;
+  place_to_insert = find_place_for_bookkeeping (e1, e2, &fence_to_rewind);
   new_seqno = find_seqno_for_bookkeeping (place_to_insert, join_point);
   need_to_exchange_data_sets
     = sel_bb_empty_p (BLOCK_FOR_INSN (place_to_insert));
 
   new_insn = emit_bookkeeping_insn (place_to_insert, c_expr, new_seqno);
 
+  if (fence_to_rewind)
+    FENCE_INSN (fence_to_rewind) = new_insn;
+
   /* When inserting bookkeeping insn in new block, av sets should be
      following: old basic block (that now holds bookkeeping) data sets are
      the same as was before generation of bookkeeping, and new basic block
@@ -5517,7 +5598,7 @@ fill_insns (fence_t fence, int seqno, ilist_t **scheduled_insns_tailpp)
     {
       blist_t *bnds_tailp1, *bndsp;
       expr_t expr_vliw;
-      int need_stall;
+      int need_stall = false;
       int was_stall = 0, scheduled_insns = 0;
       int max_insns = pipelining_p ? issue_rate : 2 * issue_rate;
       int max_stall = pipelining_p ? 1 : 3;
@@ -5695,8 +5776,8 @@ update_and_record_unavailable_insns (basic_block book_block)
               || EXPR_TARGET_AVAILABLE (new_expr)
                 != EXPR_TARGET_AVAILABLE (cur_expr))
            /* Unfortunately, the below code could be also fired up on
-              separable insns.
-              FIXME: add an example of how this could happen.  */
+              separable insns, e.g. when moving insns through the new
+              speculation check as in PR 53701.  */
             vinsn_vec_add (&vec_bookkeeping_blocked_vinsns, cur_expr);
         }
 
@@ -6675,7 +6756,7 @@ move_op (insn_t insn, av_set_t orig_ops, expr_t expr_vliw,
 {
   struct moveop_static_params sparams;
   struct cmpd_local_params lparams;
-  bool res;
+  int res;
 
   /* Init params for code_motion_path_driver.  */
   sparams.dest = dest;
@@ -6694,6 +6775,8 @@ move_op (insn_t insn, av_set_t orig_ops, expr_t expr_vliw,
   code_motion_path_driver_info = &move_op_hooks;
   res = code_motion_path_driver (insn, orig_ops, NULL, &lparams, &sparams);
 
+  gcc_assert (res != -1);
+
   if (sparams.was_renamed)
     EXPR_WAS_RENAMED (expr_vliw) = true;
 
@@ -6868,7 +6951,7 @@ sel_region_init (int rgn)
   for (i = 0; i < current_nr_blocks; i++)
     VEC_quick_push (basic_block, bbs, BASIC_BLOCK (BB_TO_BLOCK (i)));
 
-  sel_init_bbs (bbs, NULL);
+  sel_init_bbs (bbs);
 
   if (flag_sel_sched_pipelining)
     setup_current_loop_nest (rgn, &bbs);
@@ -6877,13 +6960,13 @@ sel_region_init (int rgn)
 
   /* Initialize luids and dependence analysis which both sel-sched and haifa
      need.  */
-  sched_init_luids (bbs, NULL, NULL, NULL);
+  sched_init_luids (bbs);
   sched_deps_init (false);
 
   /* Initialize haifa data.  */
   rgn_setup_sched_infos ();
   sel_set_sched_flags ();
-  haifa_init_h_i_d (bbs, NULL, NULL, NULL);
+  haifa_init_h_i_d (bbs);
 
   sel_compute_priorities (rgn);
   init_deps_global ();
@@ -7215,7 +7298,7 @@ sel_region_target_finish (bool reset_sched_cycles_p)
 
          /* Extend luids so that insns generated by the target will
             get zero luid.  */
-         sched_init_luids (NULL, NULL, NULL, NULL);
+         sched_extend_luids ();
        }
     }
 
@@ -7269,6 +7352,7 @@ sel_region_finish (bool reset_sched_cycles_p)
 
   finish_deps_global ();
   sched_finish_luids ();
+  VEC_free (haifa_deps_insn_data_def, heap, h_d_i_d);
 
   sel_finish_bbs ();
   BITMAP_FREE (blocks_to_reschedule);