Fix latent LRA remat issue (PR68730)
authorbernds <bernds@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 8 Feb 2016 15:31:08 +0000 (15:31 +0000)
committerbernds <bernds@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 8 Feb 2016 15:31:08 +0000 (15:31 +0000)
PR rtl-optimization/68730
* lra-remat.c (insn_to_cand_activation): New static variable.
(lra_remat): Allocate and free it.
(create_cand): New arg activation. Initialize a field in
insn_to_cand_activation if it is nonnull.
(create_cands): Pass the activation insn to create_cand when making
a candidate involving an output reload.  Reorganize code a little.
(do_remat): Keep track of active status of candidates in a separate
bitmap.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@233215 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/lra-remat.c

index a2fb881..66deab1 100644 (file)
@@ -1,3 +1,15 @@
+2016-02-08  Bernd Schmidt  <bschmidt@redhat.com>
+
+       PR rtl-optimization/68730
+       * lra-remat.c (insn_to_cand_activation): New static variable.
+       (lra_remat): Allocate and free it.
+       (create_cand): New arg activation. Initialize a field in
+       insn_to_cand_activation if it is nonnull.
+       (create_cands): Pass the activation insn to create_cand when making
+       a candidate involving an output reload.  Reorganize code a little.
+       (do_remat): Keep track of active status of candidates in a separate
+       bitmap.
+
 2016-02-08  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/69719
@@ -30,7 +42,6 @@
        * tree-ssa-scopedtables.c
        (const_and_copies::record_const_or_copy_raw): New, factored out of
        (const_and_copies::record_const_or_copy): Call new member function.
-       
 
 2016-02-05  Jeff Law  <law@redhat.com>
 
index e729ea9..785d531 100644 (file)
@@ -112,6 +112,10 @@ static vec<cand_t> all_cands;
 /* Map: insn -> candidate representing it.  It is null if the insn can
    not be used for rematerialization.  */
 static cand_t *insn_to_cand;
+/* A secondary map, for candidates that involve two insns, where the
+   second one makes the equivalence.  The candidate must not be used
+   before seeing this activation insn.  */
+static cand_t *insn_to_cand_activation;
 
 /* Map regno -> candidates can be used for the regno
    rematerialization.  */
@@ -461,7 +465,7 @@ operand_to_remat (rtx_insn *insn)
    REGNO.  Insert the candidate into the table and set up the
    corresponding INSN_TO_CAND element.  */
 static void
-create_cand (rtx_insn *insn, int nop, int regno)
+create_cand (rtx_insn *insn, int nop, int regno, rtx_insn *activation = NULL)
 {
   lra_insn_recog_data_t id = lra_get_insn_recog_data (insn);
   rtx reg = *id->operand_loc[nop];
@@ -486,6 +490,8 @@ create_cand (rtx_insn *insn, int nop, int regno)
       cand->next_regno_cand = regno_cands[cand->regno];
       regno_cands[cand->regno] = cand;
     }
+  if (activation)
+    insn_to_cand_activation[INSN_UID (activation)] = cand_in_table;
 }
 
 /* Create rematerialization candidates (inserting them into the
@@ -504,43 +510,55 @@ create_cands (void)
   /* Create candidates.  */
   regno_potential_cand = XCNEWVEC (struct potential_cand, max_reg_num ());
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    if (INSN_P (insn))
+    if (NONDEBUG_INSN_P (insn))
       {
-       rtx set;
-       int src_regno, dst_regno;
-       rtx_insn *insn2;
        lra_insn_recog_data_t id = lra_get_insn_recog_data (insn);
-       int nop = operand_to_remat (insn);
-       int regno = -1;
-
-       if ((set = single_set (insn)) != NULL
-           && REG_P (SET_SRC (set)) && REG_P (SET_DEST (set))
-           && ((src_regno = REGNO (SET_SRC (set)))
-               >= lra_constraint_new_regno_start)
-           && (dst_regno = REGNO (SET_DEST (set))) >= FIRST_PSEUDO_REGISTER
-           && reg_renumber[dst_regno] < 0
-           && (insn2 = regno_potential_cand[src_regno].insn) != NULL
-           && BLOCK_FOR_INSN (insn2) == BLOCK_FOR_INSN (insn))
-         /* It is an output reload insn after insn can be
-            rematerialized (potential candidate).  */
-         create_cand (insn2, regno_potential_cand[src_regno].nop, dst_regno);
-       if (nop < 0)
-         goto fail;
-       gcc_assert (REG_P (*id->operand_loc[nop]));
-       regno = REGNO (*id->operand_loc[nop]);
-       gcc_assert (regno >= FIRST_PSEUDO_REGISTER);
-       if (reg_renumber[regno] < 0)
-         create_cand (insn, nop, regno);
-       else
+       int keep_regno = -1;
+       rtx set = single_set (insn);
+       int nop;
+
+       /* See if this is an output reload for a previous insn.  */
+       if (set != NULL
+           && REG_P (SET_SRC (set)) && REG_P (SET_DEST (set)))
+         {
+           rtx dstreg = SET_DEST (set);
+           int src_regno = REGNO (SET_SRC (set));
+           int dst_regno = REGNO (dstreg);
+           rtx_insn *insn2 = regno_potential_cand[src_regno].insn;
+
+           if (insn2 != NULL 
+               && dst_regno >= FIRST_PSEUDO_REGISTER
+               && reg_renumber[dst_regno] < 0
+               && BLOCK_FOR_INSN (insn2) == BLOCK_FOR_INSN (insn))
+             {
+               create_cand (insn2, regno_potential_cand[src_regno].nop,
+                            dst_regno, insn);
+               goto done;
+             }
+         }
+
+       nop = operand_to_remat (insn);
+       if (nop >= 0)
          {
-           regno_potential_cand[regno].insn = insn;
-           regno_potential_cand[regno].nop = nop;
-           goto fail;
+           gcc_assert (REG_P (*id->operand_loc[nop]));
+           int regno = REGNO (*id->operand_loc[nop]);
+           gcc_assert (regno >= FIRST_PSEUDO_REGISTER);
+           /* If we're setting an unrenumbered pseudo, make a candidate immediately.
+              If it's an output reload register, save it for later; the code above
+              looks for output reload insns later on.  */
+           if (reg_renumber[regno] < 0)
+             create_cand (insn, nop, regno);
+           else if (regno >= lra_constraint_new_regno_start)
+             {
+               regno_potential_cand[regno].insn = insn;
+               regno_potential_cand[regno].nop = nop;
+               keep_regno = regno;
+             }
          }
-       regno = -1;
-      fail:
+
+      done:
        for (struct lra_insn_reg *reg = id->regs; reg != NULL; reg = reg->next)
-         if (reg->type != OP_IN && reg->regno != regno
+         if (reg->type != OP_IN && reg->regno != keep_regno
              && reg->regno >= FIRST_PSEUDO_REGISTER)
            regno_potential_cand[reg->regno].insn = NULL;
       }
@@ -1072,16 +1090,21 @@ do_remat (void)
   rtx_insn *insn;
   basic_block bb;
   bitmap_head avail_cands;
+  bitmap_head active_cands;
   bool changed_p = false;
   /* Living hard regs and hard registers of living pseudos.  */
   HARD_REG_SET live_hard_regs;
 
   bitmap_initialize (&avail_cands, &reg_obstack);
+  bitmap_initialize (&active_cands, &reg_obstack);
   FOR_EACH_BB_FN (bb, cfun)
     {
       REG_SET_TO_HARD_REG_SET (live_hard_regs, df_get_live_out (bb));
       bitmap_and (&avail_cands, &get_remat_bb_data (bb)->avin_cands,
                  &get_remat_bb_data (bb)->livein_cands);
+      /* Activating insns are always in the same block as their corresponding
+        remat insn, so at the start of a block the two bitsets are equal.  */
+      bitmap_copy (&active_cands, &avail_cands);
       FOR_BB_INSNS (bb, insn)
        {
          if (!NONDEBUG_INSN_P (insn))
@@ -1115,7 +1138,8 @@ do_remat (void)
              for (cand = regno_cands[src_regno];
                   cand != NULL;
                   cand = cand->next_regno_cand)
-               if (bitmap_bit_p (&avail_cands, cand->index))
+               if (bitmap_bit_p (&avail_cands, cand->index)
+                   && bitmap_bit_p (&active_cands, cand->index))
                  break;
            }
          int i, hard_regno, nregs;
@@ -1209,9 +1233,23 @@ do_remat (void)
              }
 
          bitmap_and_compl_into (&avail_cands, &temp_bitmap);
-         if ((cand = insn_to_cand[INSN_UID (insn)]) != NULL)
-           bitmap_set_bit (&avail_cands, cand->index);
-           
+
+         /* Now see whether a candidate is made active or available
+            by this insn.  */
+         cand = insn_to_cand_activation[INSN_UID (insn)];
+         if (cand)
+           bitmap_set_bit (&active_cands, cand->index);
+
+         cand = insn_to_cand[INSN_UID (insn)];
+         if (cand != NULL)
+           {
+             bitmap_set_bit (&avail_cands, cand->index);
+             if (cand->reload_regno == -1)
+               bitmap_set_bit (&active_cands, cand->index);
+             else
+               bitmap_clear_bit (&active_cands, cand->index);
+           }
+
          if (remat_insn != NULL)
            {
              HOST_WIDE_INT sp_offset_change = cand_sp_offset - id->sp_offset;
@@ -1258,6 +1296,7 @@ do_remat (void)
        }
     }
   bitmap_clear (&avail_cands);
+  bitmap_clear (&active_cands);
   return changed_p;
 }
 
@@ -1286,6 +1325,7 @@ lra_remat (void)
             lra_rematerialization_iter);
   timevar_push (TV_LRA_REMAT);
   insn_to_cand = XCNEWVEC (cand_t, get_max_uid ());
+  insn_to_cand_activation = XCNEWVEC (cand_t, get_max_uid ());
   regno_cands = XCNEWVEC (cand_t, max_regno);
   all_cands.create (8000);
   call_used_regs_arr_len = 0;
@@ -1314,6 +1354,7 @@ lra_remat (void)
   bitmap_clear (&all_blocks);
   free (regno_cands);
   free (insn_to_cand);
+  free (insn_to_cand_activation);
   timevar_pop (TV_LRA_REMAT);
   return result;
 }