cse support for clobber_high
authorAlan Hayward <alan.hayward@arm.com>
Mon, 6 Aug 2018 09:54:28 +0000 (09:54 +0000)
committerAlan Hayward <alahay01@gcc.gnu.org>
Mon, 6 Aug 2018 09:54:28 +0000 (09:54 +0000)
gcc/
* cse.c (invalidate_reg): New function extracted from...
(invalidate): ...here.
(canonicalize_insn): Check for clobber high.
(invalidate_from_clobbers): invalidate clobber highs.
(invalidate_from_sets_and_clobbers): Likewise.
(count_reg_usage): Check for clobber high.
(insn_live_p): Likewise.
* cselib.c (cselib_expand_value_rtx_1):Likewise.
(cselib_invalidate_regno): Check for clobber in setter.
(cselib_invalidate_rtx): Pass through setter.
(cselib_invalidate_rtx_note_stores):
(cselib_process_insn): Check for clobber high.
* cselib.h (cselib_invalidate_rtx): Add operand.

From-SVN: r263330

gcc/ChangeLog
gcc/cse.c
gcc/cselib.c
gcc/cselib.h

index 8d9b158861d667bf917bd50361ce68ea09fbd5d0..883399fd2d108752898b56a153a6e6d023833056 100644 (file)
@@ -1,3 +1,19 @@
+2018-08-06  Alan Hayward  <alan.hayward@arm.com>
+
+       * cse.c (invalidate_reg): New function extracted from...
+       (invalidate): ...here.
+       (canonicalize_insn): Check for clobber high.
+       (invalidate_from_clobbers): invalidate clobber highs.
+       (invalidate_from_sets_and_clobbers): Likewise.
+       (count_reg_usage): Check for clobber high.
+       (insn_live_p): Likewise.
+       * cselib.c (cselib_expand_value_rtx_1):Likewise.
+       (cselib_invalidate_regno): Check for clobber in setter.
+       (cselib_invalidate_rtx): Pass through setter.
+       (cselib_invalidate_rtx_note_stores):
+       (cselib_process_insn): Check for clobber high.
+       * cselib.h (cselib_invalidate_rtx): Add operand.
+
 2018-08-06  Alan Hayward  <alan.hayward@arm.com>
 
        * lra-eliminations.c (lra_eliminate_regs_1): Check for clobber high.
index 4e94152b38047d336052f81d93a6d49c3ae2de2a..3d7888b709375b7ea99eb56a9a61c194307956bc 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -559,6 +559,7 @@ static struct table_elt *insert_with_costs (rtx, struct table_elt *, unsigned,
 static struct table_elt *insert (rtx, struct table_elt *, unsigned,
                                 machine_mode);
 static void merge_equiv_classes (struct table_elt *, struct table_elt *);
+static void invalidate_reg (rtx, bool);
 static void invalidate (rtx, machine_mode);
 static void remove_invalid_refs (unsigned int);
 static void remove_invalid_subreg_refs (unsigned int, poly_uint64,
@@ -1818,7 +1819,85 @@ check_dependence (const_rtx x, rtx exp, machine_mode mode, rtx addr)
     }
   return false;
 }
-\f
+
+/* Remove from the hash table, or mark as invalid, all expressions whose
+   values could be altered by storing in register X.
+
+   CLOBBER_HIGH is set if X was part of a CLOBBER_HIGH expression.  */
+
+static void
+invalidate_reg (rtx x, bool clobber_high)
+{
+  gcc_assert (GET_CODE (x) == REG);
+
+  /* If X is a register, dependencies on its contents are recorded
+     through the qty number mechanism.  Just change the qty number of
+     the register, mark it as invalid for expressions that refer to it,
+     and remove it itself.  */
+  unsigned int regno = REGNO (x);
+  unsigned int hash = HASH (x, GET_MODE (x));
+
+  /* Remove REGNO from any quantity list it might be on and indicate
+     that its value might have changed.  If it is a pseudo, remove its
+     entry from the hash table.
+
+     For a hard register, we do the first two actions above for any
+     additional hard registers corresponding to X.  Then, if any of these
+     registers are in the table, we must remove any REG entries that
+     overlap these registers.  */
+
+  delete_reg_equiv (regno);
+  REG_TICK (regno)++;
+  SUBREG_TICKED (regno) = -1;
+
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    {
+      gcc_assert (!clobber_high);
+      remove_pseudo_from_table (x, hash);
+    }
+  else
+    {
+      HOST_WIDE_INT in_table = TEST_HARD_REG_BIT (hard_regs_in_table, regno);
+      unsigned int endregno = END_REGNO (x);
+      unsigned int rn;
+      struct table_elt *p, *next;
+
+      CLEAR_HARD_REG_BIT (hard_regs_in_table, regno);
+
+      for (rn = regno + 1; rn < endregno; rn++)
+       {
+         in_table |= TEST_HARD_REG_BIT (hard_regs_in_table, rn);
+         CLEAR_HARD_REG_BIT (hard_regs_in_table, rn);
+         delete_reg_equiv (rn);
+         REG_TICK (rn)++;
+         SUBREG_TICKED (rn) = -1;
+       }
+
+      if (in_table)
+       for (hash = 0; hash < HASH_SIZE; hash++)
+         for (p = table[hash]; p; p = next)
+           {
+             next = p->next_same_hash;
+
+             if (!REG_P (p->exp) || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
+               continue;
+
+             if (clobber_high)
+               {
+                 if (reg_is_clobbered_by_clobber_high (p->exp, x))
+                   remove_from_table (p, hash);
+               }
+             else
+               {
+                 unsigned int tregno = REGNO (p->exp);
+                 unsigned int tendregno = END_REGNO (p->exp);
+                 if (tendregno > regno && tregno < endregno)
+                   remove_from_table (p, hash);
+               }
+           }
+    }
+}
+
 /* Remove from the hash table, or mark as invalid, all expressions whose
    values could be altered by storing in X.  X is a register, a subreg, or
    a memory reference with nonvarying address (because, when a memory
@@ -1841,65 +1920,7 @@ invalidate (rtx x, machine_mode full_mode)
   switch (GET_CODE (x))
     {
     case REG:
-      {
-       /* If X is a register, dependencies on its contents are recorded
-          through the qty number mechanism.  Just change the qty number of
-          the register, mark it as invalid for expressions that refer to it,
-          and remove it itself.  */
-       unsigned int regno = REGNO (x);
-       unsigned int hash = HASH (x, GET_MODE (x));
-
-       /* Remove REGNO from any quantity list it might be on and indicate
-          that its value might have changed.  If it is a pseudo, remove its
-          entry from the hash table.
-
-          For a hard register, we do the first two actions above for any
-          additional hard registers corresponding to X.  Then, if any of these
-          registers are in the table, we must remove any REG entries that
-          overlap these registers.  */
-
-       delete_reg_equiv (regno);
-       REG_TICK (regno)++;
-       SUBREG_TICKED (regno) = -1;
-
-       if (regno >= FIRST_PSEUDO_REGISTER)
-         remove_pseudo_from_table (x, hash);
-       else
-         {
-           HOST_WIDE_INT in_table
-             = TEST_HARD_REG_BIT (hard_regs_in_table, regno);
-           unsigned int endregno = END_REGNO (x);
-           unsigned int tregno, tendregno, rn;
-           struct table_elt *p, *next;
-
-           CLEAR_HARD_REG_BIT (hard_regs_in_table, regno);
-
-           for (rn = regno + 1; rn < endregno; rn++)
-             {
-               in_table |= TEST_HARD_REG_BIT (hard_regs_in_table, rn);
-               CLEAR_HARD_REG_BIT (hard_regs_in_table, rn);
-               delete_reg_equiv (rn);
-               REG_TICK (rn)++;
-               SUBREG_TICKED (rn) = -1;
-             }
-
-           if (in_table)
-             for (hash = 0; hash < HASH_SIZE; hash++)
-               for (p = table[hash]; p; p = next)
-                 {
-                   next = p->next_same_hash;
-
-                   if (!REG_P (p->exp)
-                       || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
-                     continue;
-
-                   tregno = REGNO (p->exp);
-                   tendregno = END_REGNO (p->exp);
-                   if (tendregno > regno && tregno < endregno)
-                     remove_from_table (p, hash);
-                 }
-         }
-      }
+      invalidate_reg (x, false);
       return;
 
     case SUBREG:
@@ -4399,6 +4420,8 @@ canonicalize_insn (rtx_insn *insn, struct set **psets, int n_sets)
       if (MEM_P (XEXP (x, 0)))
        canon_reg (XEXP (x, 0), insn);
     }
+  else if (GET_CODE (x) == CLOBBER_HIGH)
+    gcc_assert (REG_P (XEXP (x, 0)));
   else if (GET_CODE (x) == USE
           && ! (REG_P (XEXP (x, 0))
                 && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER))
@@ -4430,6 +4453,8 @@ canonicalize_insn (rtx_insn *insn, struct set **psets, int n_sets)
              if (MEM_P (XEXP (y, 0)))
                canon_reg (XEXP (y, 0), insn);
            }
+         else if (GET_CODE (y) == CLOBBER_HIGH)
+           gcc_assert (REG_P (XEXP (y, 0)));
          else if (GET_CODE (y) == USE
                   && ! (REG_P (XEXP (y, 0))
                         && REGNO (XEXP (y, 0)) < FIRST_PSEUDO_REGISTER))
@@ -6130,6 +6155,12 @@ invalidate_from_clobbers (rtx_insn *insn)
            invalidate (XEXP (ref, 0), GET_MODE (ref));
        }
     }
+  if (GET_CODE (x) == CLOBBER_HIGH)
+    {
+      rtx ref = XEXP (x, 0);
+      gcc_assert (REG_P (ref));
+      invalidate_reg (ref, true);
+    }
   else if (GET_CODE (x) == PARALLEL)
     {
       int i;
@@ -6146,6 +6177,12 @@ invalidate_from_clobbers (rtx_insn *insn)
                       || GET_CODE (ref) == ZERO_EXTRACT)
                invalidate (XEXP (ref, 0), GET_MODE (ref));
            }
+         else if (GET_CODE (y) == CLOBBER_HIGH)
+           {
+             rtx ref = XEXP (y, 0);
+             gcc_assert (REG_P (ref));
+             invalidate_reg (ref, true);
+           }
        }
     }
 }
@@ -6163,8 +6200,17 @@ invalidate_from_sets_and_clobbers (rtx_insn *insn)
   if (CALL_P (insn))
     {
       for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
-       if (GET_CODE (XEXP (tem, 0)) == CLOBBER)
-         invalidate (SET_DEST (XEXP (tem, 0)), VOIDmode);
+       {
+         rtx temx = XEXP (tem, 0);
+         if (GET_CODE (temx) == CLOBBER)
+           invalidate (SET_DEST (temx), VOIDmode);
+         else if (GET_CODE (temx) == CLOBBER_HIGH)
+           {
+             rtx temref = XEXP (temx, 0);
+             gcc_assert (REG_P (temref));
+             invalidate_reg (temref, true);
+           }
+       }
     }
 
   /* Ensure we invalidate the destination register of a CALL insn.
@@ -6191,6 +6237,12 @@ invalidate_from_sets_and_clobbers (rtx_insn *insn)
                       || GET_CODE (clobbered) == ZERO_EXTRACT)
                invalidate (XEXP (clobbered, 0), GET_MODE (clobbered));
            }
+         else if (GET_CODE (y) == CLOBBER_HIGH)
+           {
+             rtx ref = XEXP (y, 0);
+             gcc_assert (REG_P (ref));
+             invalidate_reg (ref, true);
+           }
          else if (GET_CODE (y) == SET && GET_CODE (SET_SRC (y)) == CALL)
            invalidate (SET_DEST (y), VOIDmode);
        }
@@ -6850,6 +6902,10 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
        count_reg_usage (XEXP (XEXP (x, 0), 0), counts, NULL_RTX, incr);
       return;
 
+    case CLOBBER_HIGH:
+      gcc_assert (REG_P ((XEXP (x, 0))));
+      return;
+
     case SET:
       /* Unless we are setting a REG, count everything in SET_DEST.  */
       if (!REG_P (SET_DEST (x)))
@@ -6902,7 +6958,8 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
          || (REG_NOTE_KIND (x) != REG_NONNEG && GET_CODE (XEXP (x,0)) == USE)
          /* FUNCTION_USAGE expression lists may include (CLOBBER (mem /u)),
             involving registers in the address.  */
-         || GET_CODE (XEXP (x, 0)) == CLOBBER)
+         || GET_CODE (XEXP (x, 0)) == CLOBBER
+         || GET_CODE (XEXP (x, 0)) == CLOBBER_HIGH)
        count_reg_usage (XEXP (x, 0), counts, NULL_RTX, incr);
 
       count_reg_usage (XEXP (x, 1), counts, NULL_RTX, incr);
@@ -6986,7 +7043,9 @@ insn_live_p (rtx_insn *insn, int *counts)
              if (set_live_p (elt, insn, counts))
                return true;
            }
-         else if (GET_CODE (elt) != CLOBBER && GET_CODE (elt) != USE)
+         else if (GET_CODE (elt) != CLOBBER
+                  && GET_CODE (elt) != CLOBBER_HIGH
+                  && GET_CODE (elt) != USE)
            return true;
        }
       return false;
index 5a978c1f4b8a8a86a2bd9dbbd5628cd5c5f86b3d..6d3a4078c689db272f39ed80acbff922c780f906 100644 (file)
@@ -54,7 +54,8 @@ static unsigned int cselib_hash_rtx (rtx, int, machine_mode);
 static cselib_val *new_cselib_val (unsigned int, machine_mode, rtx);
 static void add_mem_for_addr (cselib_val *, cselib_val *, rtx);
 static cselib_val *cselib_lookup_mem (rtx, int);
-static void cselib_invalidate_regno (unsigned int, machine_mode);
+static void cselib_invalidate_regno (unsigned int, machine_mode,
+                                    const_rtx = NULL);
 static void cselib_invalidate_mem (rtx);
 static void cselib_record_set (rtx, cselib_val *, cselib_val *);
 static void cselib_record_sets (rtx_insn *);
@@ -1661,6 +1662,7 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd,
       /* SCRATCH must be shared because they represent distinct values.  */
       return orig;
     case CLOBBER:
+    case CLOBBER_HIGH:
       if (REG_P (XEXP (orig, 0)) && HARD_REGISTER_NUM_P (REGNO (XEXP (orig, 0))))
        return orig;
       break;
@@ -2163,7 +2165,8 @@ cselib_lookup (rtx x, machine_mode mode,
    invalidating call clobbered registers across a call.  */
 
 static void
-cselib_invalidate_regno (unsigned int regno, machine_mode mode)
+cselib_invalidate_regno (unsigned int regno, machine_mode mode,
+                        const_rtx setter)
 {
   unsigned int endregno;
   unsigned int i;
@@ -2186,6 +2189,9 @@ cselib_invalidate_regno (unsigned int regno, machine_mode mode)
        i = regno - max_value_regs;
 
       endregno = end_hard_regno (mode, regno);
+
+      if (setter && GET_CODE (setter) == CLOBBER_HIGH)
+       gcc_assert (endregno == regno + 1);
     }
   else
     {
@@ -2218,6 +2224,19 @@ cselib_invalidate_regno (unsigned int regno, machine_mode mode)
              continue;
            }
 
+         /* Ignore if clobber high and the register isn't clobbered.  */
+         if (setter && GET_CODE (setter) == CLOBBER_HIGH)
+           {
+             gcc_assert (endregno == regno + 1);
+             const_rtx x = XEXP (setter, 0);
+             if (!reg_is_clobbered_by_clobber_high (i, GET_MODE (v->val_rtx),
+                                                    x))
+               {
+                 l = &(*l)->next;
+                 continue;
+               }
+           }
+
          /* We have an overlap.  */
          if (*l == REG_VALUES (i))
            {
@@ -2352,10 +2371,10 @@ cselib_invalidate_mem (rtx mem_rtx)
   *vp = &dummy_val;
 }
 
-/* Invalidate DEST, which is being assigned to or clobbered.  */
+/* Invalidate DEST, which is being assigned to or clobbered by SETTER.  */
 
 void
-cselib_invalidate_rtx (rtx dest)
+cselib_invalidate_rtx (rtx dest, const_rtx setter)
 {
   while (GET_CODE (dest) == SUBREG
         || GET_CODE (dest) == ZERO_EXTRACT
@@ -2363,7 +2382,7 @@ cselib_invalidate_rtx (rtx dest)
     dest = XEXP (dest, 0);
 
   if (REG_P (dest))
-    cselib_invalidate_regno (REGNO (dest), GET_MODE (dest));
+    cselib_invalidate_regno (REGNO (dest), GET_MODE (dest), setter);
   else if (MEM_P (dest))
     cselib_invalidate_mem (dest);
 }
@@ -2371,10 +2390,10 @@ cselib_invalidate_rtx (rtx dest)
 /* A wrapper for cselib_invalidate_rtx to be called via note_stores.  */
 
 static void
-cselib_invalidate_rtx_note_stores (rtx dest, const_rtx ignore ATTRIBUTE_UNUSED,
+cselib_invalidate_rtx_note_stores (rtx dest, const_rtx setter,
                                   void *data ATTRIBUTE_UNUSED)
 {
-  cselib_invalidate_rtx (dest);
+  cselib_invalidate_rtx (dest, setter);
 }
 
 /* Record the result of a SET instruction.  DEST is being set; the source
@@ -2775,9 +2794,12 @@ cselib_process_insn (rtx_insn *insn)
   if (CALL_P (insn))
     {
       for (x = CALL_INSN_FUNCTION_USAGE (insn); x; x = XEXP (x, 1))
-       if (GET_CODE (XEXP (x, 0)) == CLOBBER)
-         cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0));
-      /* Flush evertything on setjmp.  */
+       {
+         gcc_assert (GET_CODE (XEXP (x, 0)) != CLOBBER_HIGH);
+         if (GET_CODE (XEXP (x, 0)) == CLOBBER)
+           cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0));
+       }
+      /* Flush everything on setjmp.  */
       if (cselib_preserve_constants
          && find_reg_note (insn, REG_SETJMP, NULL))
        {
index be6feaf84deeee420568961b2ceaf89197b79d9c..0005ad3113cd26126c9014fb064057566b899919 100644 (file)
@@ -92,7 +92,7 @@ extern bool cselib_dummy_expand_value_rtx_cb (rtx, bitmap, int,
                                              cselib_expand_callback, void *);
 extern rtx cselib_subst_to_values (rtx, machine_mode);
 extern rtx cselib_subst_to_values_from_insn (rtx, machine_mode, rtx_insn *);
-extern void cselib_invalidate_rtx (rtx);
+extern void cselib_invalidate_rtx (rtx, const_rtx = NULL);
 
 extern void cselib_reset_table (unsigned int);
 extern unsigned int cselib_get_next_uid (void);