[26/46] Make more use of dyn_cast in tree-vect*
[gcc.git] / gcc / regrename.c
index c328c1b916c6661e698c61ef58652f89b352507d..84240930e3a5b14ec648fb977b9323580b585233 100644 (file)
@@ -1,5 +1,5 @@
 /* Register renaming for the GNU compiler.
-   Copyright (C) 2000-2015 Free Software Foundation, Inc.
+   Copyright (C) 2000-2018 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
 #include "system.h"
 #include "coretypes.h"
 #include "backend.h"
+#include "target.h"
 #include "rtl.h"
 #include "df.h"
-#include "rtl-error.h"
+#include "memmodel.h"
 #include "tm_p.h"
 #include "insn-config.h"
 #include "regs.h"
+#include "emit-rtl.h"
+#include "recog.h"
 #include "addresses.h"
 #include "cfganal.h"
-#include "reload.h"
-#include "output.h"
-#include "recog.h"
-#include "flags.h"
 #include "tree-pass.h"
-#include "target.h"
-#include "emit-rtl.h"
 #include "regrename.h"
 
 /* This file implements the RTL register renaming pass of the compiler.  It is
      5. If a renaming register has been found, it is substituted in the chain.
 
   Targets can parameterize the pass by specifying a preferred class for the
-  renaming register for a given (super)class of registers to be renamed.  */
+  renaming register for a given (super)class of registers to be renamed.
+
+  DEBUG_INSNs are treated specially, in particular registers occurring inside
+  them are treated as requiring ALL_REGS as a class.  */
 
 #if HOST_BITS_PER_WIDE_INT <= MAX_RECOG_OPERANDS
 #error "Use a different bitmap implementation for untracked_operands."
@@ -134,6 +134,9 @@ static HARD_REG_SET live_hard_regs;
    record_operand_use.  */
 static operand_rr_info *cur_operand;
 
+/* Set while scanning RTL if a register dies.  Used to tie chains.  */
+static struct du_head *terminated_this_insn;
+
 /* Return the chain corresponding to id number ID.  Take into account that
    chains may have been merged.  */
 du_head_p
@@ -204,8 +207,13 @@ mark_conflict (struct du_head *chains, unsigned id)
 static void
 record_operand_use (struct du_head *head, struct du_chain *this_du)
 {
-  if (cur_operand == NULL)
+  if (cur_operand == NULL || cur_operand->failed)
     return;
+  if (head->cannot_rename)
+    {
+      cur_operand->failed = true;
+      return;
+    }
   gcc_assert (cur_operand->n_chains < MAX_REGS_PER_ADDRESS);
   cur_operand->heads[cur_operand->n_chains] = head;
   cur_operand->chains[cur_operand->n_chains++] = this_du;
@@ -223,11 +231,10 @@ create_new_chain (unsigned this_regno, unsigned this_nregs, rtx *loc,
   struct du_chain *this_du;
   int nregs;
 
+  memset (head, 0, sizeof *head);
   head->next_chain = open_chains;
   head->regno = this_regno;
   head->nregs = this_nregs;
-  head->need_caller_save_reg = 0;
-  head->cannot_rename = 0;
 
   id_to_chain.safe_push (head);
   head->id = current_id++;
@@ -305,7 +312,7 @@ check_new_reg_p (int reg ATTRIBUTE_UNUSED, int new_reg,
                 struct du_head *this_head, HARD_REG_SET this_unavailable)
 {
   machine_mode mode = GET_MODE (*this_head->first->loc);
-  int nregs = hard_regno_nregs[new_reg][mode];
+  int nregs = hard_regno_nregs (new_reg, mode);
   int i;
   struct du_chain *tmp;
 
@@ -328,12 +335,12 @@ check_new_reg_p (int reg ATTRIBUTE_UNUSED, int new_reg,
   /* See whether it accepts all modes that occur in
      definition and uses.  */
   for (tmp = this_head->first; tmp; tmp = tmp->next_use)
-    if ((! HARD_REGNO_MODE_OK (new_reg, GET_MODE (*tmp->loc))
+    if ((!targetm.hard_regno_mode_ok (new_reg, GET_MODE (*tmp->loc))
         && ! DEBUG_INSN_P (tmp->insn))
        || (this_head->need_caller_save_reg
-           && ! (HARD_REGNO_CALL_PART_CLOBBERED
+           && ! (targetm.hard_regno_call_part_clobbered
                  (reg, GET_MODE (*tmp->loc)))
-           && (HARD_REGNO_CALL_PART_CLOBBERED
+           && (targetm.hard_regno_call_part_clobbered
                (new_reg, GET_MODE (*tmp->loc)))))
       return false;
 
@@ -370,6 +377,13 @@ find_rename_reg (du_head_p this_head, enum reg_class super_class,
   preferred_class
     = (enum reg_class) targetm.preferred_rename_class (super_class);
 
+  /* Pick and check the register from the tied chain iff the tied chain
+     is not renamed.  */
+  if (this_head->tied_chain && !this_head->tied_chain->renamed
+      && check_new_reg_p (old_reg, this_head->tied_chain->regno,
+                         this_head, *unavailable))
+    return this_head->tied_chain->regno;
+
   /* If PREFERRED_CLASS is not NO_REGS, we iterate in the first pass
      over registers that belong to PREFERRED_CLASS and try to find the
      best register within the class.  If that failed, we iterate in
@@ -409,6 +423,33 @@ find_rename_reg (du_head_p this_head, enum reg_class super_class,
   return best_new_reg;
 }
 
+/* Iterate over elements in the chain HEAD in order to:
+   1. Count number of uses, storing it in *PN_USES.
+   2. Narrow the set of registers we can use for renaming, adding
+      unavailable registers to *PUNAVAILABLE, which must be
+      initialized by the caller.
+   3. Compute the superunion of register classes in this chain
+      and return it.  */
+reg_class
+regrename_find_superclass (du_head_p head, int *pn_uses,
+                          HARD_REG_SET *punavailable)
+{
+  int n_uses = 0;
+  reg_class super_class = NO_REGS;
+  for (du_chain *tmp = head->first; tmp; tmp = tmp->next_use)
+    {
+      if (DEBUG_INSN_P (tmp->insn))
+       continue;
+      n_uses++;
+      IOR_COMPL_HARD_REG_SET (*punavailable,
+                             reg_class_contents[tmp->cl]);
+      super_class
+       = reg_class_superunion[(int) super_class][(int) tmp->cl];
+    }
+  *pn_uses = n_uses;
+  return super_class;
+}
+
 /* Perform register renaming on the current function.  */
 static void
 rename_chains (void)
@@ -432,10 +473,8 @@ rename_chains (void)
     {
       int best_new_reg;
       int n_uses;
-      struct du_chain *tmp;
       HARD_REG_SET this_unavailable;
       int reg = this_head->regno;
-      enum reg_class super_class = NO_REGS;
 
       if (this_head->cannot_rename)
        continue;
@@ -443,29 +482,14 @@ rename_chains (void)
       if (fixed_regs[reg] || global_regs[reg]
          || (!HARD_FRAME_POINTER_IS_FRAME_POINTER && frame_pointer_needed
              && reg == HARD_FRAME_POINTER_REGNUM)
-         || (HARD_FRAME_POINTER_REGNUM && frame_pointer_needed
+         || (HARD_FRAME_POINTER_IS_FRAME_POINTER && frame_pointer_needed
              && reg == FRAME_POINTER_REGNUM))
        continue;
 
       COPY_HARD_REG_SET (this_unavailable, unavailable);
 
-      /* Iterate over elements in the chain in order to:
-        1. Count number of uses, and narrow the set of registers we can
-           use for renaming.
-        2. Compute the superunion of register classes in this chain.  */
-      n_uses = 0;
-      super_class = NO_REGS;
-      for (tmp = this_head->first; tmp; tmp = tmp->next_use)
-       {
-         if (DEBUG_INSN_P (tmp->insn))
-           continue;
-         n_uses++;
-         IOR_COMPL_HARD_REG_SET (this_unavailable,
-                                 reg_class_contents[tmp->cl]);
-         super_class
-           = reg_class_superunion[(int) super_class][(int) tmp->cl];
-       }
-
+      reg_class super_class = regrename_find_superclass (this_head, &n_uses,
+                                                        &this_unavailable);
       if (n_uses < 2)
        continue;
 
@@ -939,6 +963,7 @@ regrename_do_replace (struct du_head *head, int reg)
   struct du_chain *chain;
   unsigned int base_regno = head->regno;
   machine_mode mode;
+  rtx last_reg = NULL_RTX, last_repl = NULL_RTX;
 
   for (chain = head->first; chain; chain = chain->next_use)
     {
@@ -951,12 +976,16 @@ regrename_do_replace (struct du_head *head, int reg)
                         gen_rtx_UNKNOWN_VAR_LOC (), true);
       else
        {
-         validate_change (chain->insn, chain->loc, 
-                          gen_raw_REG (GET_MODE (*chain->loc), reg), true);
-         if (regno >= FIRST_PSEUDO_REGISTER)
-           ORIGINAL_REGNO (*chain->loc) = regno;
-         REG_ATTRS (*chain->loc) = attr;
-         REG_POINTER (*chain->loc) = reg_ptr;
+         if (*chain->loc != last_reg)
+           {
+             last_repl = gen_raw_REG (GET_MODE (*chain->loc), reg);
+             if (regno >= FIRST_PSEUDO_REGISTER)
+               ORIGINAL_REGNO (last_repl) = regno;
+             REG_ATTRS (last_repl) = attr;
+             REG_POINTER (last_repl) = reg_ptr;
+             last_reg = *chain->loc;
+           }
+         validate_change (chain->insn, chain->loc, last_repl, true);
        }
     }
 
@@ -964,8 +993,9 @@ regrename_do_replace (struct du_head *head, int reg)
     return false;
 
   mode = GET_MODE (*head->first->loc);
+  head->renamed = 1;
   head->regno = reg;
-  head->nregs = hard_regno_nregs[reg][mode];
+  head->nregs = hard_regno_nregs (reg, mode);
   return true;
 }
 
@@ -1047,7 +1077,36 @@ scan_rtx_reg (rtx_insn *insn, rtx *loc, enum reg_class cl, enum scan_actions act
   if (action == mark_write)
     {
       if (type == OP_OUT)
-       create_new_chain (this_regno, this_nregs, loc, insn, cl);
+       {
+         du_head_p c;
+         rtx pat = PATTERN (insn);
+
+         c = create_new_chain (this_regno, this_nregs, loc, insn, cl);
+
+         /* We try to tie chains in a move instruction for
+            a single output.  */
+         if (recog_data.n_operands == 2
+             && GET_CODE (pat) == SET
+             && GET_CODE (SET_DEST (pat)) == REG
+             && GET_CODE (SET_SRC (pat)) == REG
+             && terminated_this_insn
+             && terminated_this_insn->nregs
+                == REG_NREGS (recog_data.operand[1]))
+           {
+             gcc_assert (terminated_this_insn->regno
+                         == REGNO (recog_data.operand[1]));
+
+             c->tied_chain = terminated_this_insn;
+             terminated_this_insn->tied_chain = c;
+
+             if (dump_file)
+               fprintf (dump_file, "Tying chain %s (%d) with %s (%d)\n",
+                        reg_names[c->regno], c->id,
+                        reg_names[terminated_this_insn->regno],
+                        terminated_this_insn->id);
+           }
+       }
+
       return;
     }
 
@@ -1155,6 +1214,8 @@ scan_rtx_reg (rtx_insn *insn, rtx *loc, enum reg_class cl, enum scan_actions act
                SET_HARD_REG_BIT (live_hard_regs, head->regno + nregs);
            }
 
+         if (action == terminate_dead)
+           terminated_this_insn = *p;
          *p = next;
          if (dump_file)
            fprintf (dump_file,
@@ -1186,6 +1247,19 @@ scan_rtx_reg (rtx_insn *insn, rtx *loc, enum reg_class cl, enum scan_actions act
     }
 }
 
+/* A wrapper around base_reg_class which returns ALL_REGS if INSN is a
+   DEBUG_INSN.  The arguments MODE, AS, CODE and INDEX_CODE are as for
+   base_reg_class.  */
+
+static reg_class
+base_reg_class_for_rename (rtx_insn *insn, machine_mode mode, addr_space_t as,
+                          rtx_code code, rtx_code index_code)
+{
+  if (DEBUG_INSN_P (insn))
+    return ALL_REGS;
+  return base_reg_class (mode, as, code, index_code);
+}
+
 /* Adapted from find_reloads_address_1.  CL is INDEX_REG_CLASS or
    BASE_REG_CLASS depending on how the register is being considered.  */
 
@@ -1291,12 +1365,16 @@ scan_rtx_address (rtx_insn *insn, rtx *loc, enum reg_class cl,
          }
 
        if (locI)
-         scan_rtx_address (insn, locI, INDEX_REG_CLASS, action, mode, as);
+         {
+           reg_class iclass = DEBUG_INSN_P (insn) ? ALL_REGS : INDEX_REG_CLASS;
+           scan_rtx_address (insn, locI, iclass, action, mode, as);
+         }
        if (locB)
-         scan_rtx_address (insn, locB,
-                           base_reg_class (mode, as, PLUS, index_code),
-                           action, mode, as);
-
+         {
+           reg_class bclass = base_reg_class_for_rename (insn, mode, as, PLUS,
+                                                         index_code);
+           scan_rtx_address (insn, locB, bclass, action, mode, as);
+         }
        return;
       }
 
@@ -1308,16 +1386,19 @@ scan_rtx_address (rtx_insn *insn, rtx *loc, enum reg_class cl,
     case PRE_MODIFY:
       /* If the target doesn't claim to handle autoinc, this must be
         something special, like a stack push.  Kill this chain.  */
-    if (!AUTO_INC_DEC)
-      action = mark_all_read;
+      if (!AUTO_INC_DEC)
+       action = mark_all_read;
 
       break;
 
     case MEM:
-      scan_rtx_address (insn, &XEXP (x, 0),
-                       base_reg_class (GET_MODE (x), MEM_ADDR_SPACE (x),
-                                       MEM, SCRATCH),
-                       action, GET_MODE (x), MEM_ADDR_SPACE (x));
+      {
+       reg_class bclass = base_reg_class_for_rename (insn, GET_MODE (x),
+                                                     MEM_ADDR_SPACE (x),
+                                                     MEM, SCRATCH);
+       scan_rtx_address (insn, &XEXP (x, 0), bclass, action, GET_MODE (x),
+                         MEM_ADDR_SPACE (x));
+      }
       return;
 
     case REG:
@@ -1364,10 +1445,14 @@ scan_rtx (rtx_insn *insn, rtx *loc, enum reg_class cl, enum scan_actions action,
       return;
 
     case MEM:
-      scan_rtx_address (insn, &XEXP (x, 0),
-                       base_reg_class (GET_MODE (x), MEM_ADDR_SPACE (x),
-                                       MEM, SCRATCH),
-                       action, GET_MODE (x), MEM_ADDR_SPACE (x));
+      {
+       reg_class bclass = base_reg_class_for_rename (insn, GET_MODE (x),
+                                                     MEM_ADDR_SPACE (x),
+                                                     MEM, SCRATCH);
+
+       scan_rtx_address (insn, &XEXP (x, 0), bclass, action, GET_MODE (x),
+                         MEM_ADDR_SPACE (x));
+      }
       return;
 
     case SET:
@@ -1513,6 +1598,8 @@ record_out_operands (rtx_insn *insn, bool earlyclobber, insn_rr_info *insn_info)
        cur_operand = insn_info->op_info + i;
 
       prev_open = open_chains;
+      if (earlyclobber)
+       scan_rtx (insn, loc, cl, terminate_write, OP_OUT);
       scan_rtx (insn, loc, cl, mark_write, OP_OUT);
 
       /* ??? Many targets have output constraints on the SET_DEST
@@ -1555,6 +1642,7 @@ build_def_use (basic_block bb)
          enum rtx_code set_code = SET;
          enum rtx_code clobber_code = CLOBBER;
          insn_rr_info *insn_info = NULL;
+         terminated_this_insn = NULL;
 
          /* Process the insn, determining its effect on the def-use
             chains and live hard registers.  We perform the following
@@ -1573,6 +1661,8 @@ build_def_use (basic_block bb)
             (6) For any non-earlyclobber write we find in an operand, make
                 a new chain or mark the hard register as live.
             (7) For any REG_UNUSED, close any chains we just opened.
+            (8) For any REG_CFA_RESTORE or REG_CFA_REGISTER, kill any chain
+                containing its dest.
 
             We cannot deal with situations where we track a reg in one mode
             and see a reference in another mode; these will cause the chain
@@ -1613,15 +1703,27 @@ build_def_use (basic_block bb)
                     not already tracking such a reg, we won't start here,
                     and we must instead make sure to make the operand visible
                     to the machinery that tracks hard registers.  */
-                 if (matches >= 0
-                     && (GET_MODE_SIZE (recog_data.operand_mode[i])
-                         != GET_MODE_SIZE (recog_data.operand_mode[matches]))
-                     && !verify_reg_in_set (op, &live_in_chains))
+                 machine_mode i_mode = recog_data.operand_mode[i];
+                 if (matches >= 0)
                    {
-                     untracked_operands |= 1 << i;
-                     untracked_operands |= 1 << matches;
+                     machine_mode matches_mode
+                       = recog_data.operand_mode[matches];
+
+                     if (maybe_ne (GET_MODE_SIZE (i_mode),
+                                   GET_MODE_SIZE (matches_mode))
+                         && !verify_reg_in_set (op, &live_in_chains))
+                       {
+                         untracked_operands |= 1 << i;
+                         untracked_operands |= 1 << matches;
+                       }
                    }
                }
+#ifdef STACK_REGS
+             if (regstack_completed
+                 && REG_P (op)
+                 && IN_RANGE (REGNO (op), FIRST_STACK_REG, LAST_STACK_REG))
+               untracked_operands |= 1 << i;
+#endif
              /* If there's an in-out operand with a register that is not
                 being tracked at all yet, open a chain.  */
              if (recog_data.operand_type[i] == OP_INOUT
@@ -1779,8 +1881,24 @@ build_def_use (basic_block bb)
                scan_rtx (insn, &XEXP (note, 0), NO_REGS, terminate_dead,
                          OP_IN);
              }
+
+         /* Step 8: Kill the chains involving register restores.  Those
+            should restore _that_ register.  Similar for REG_CFA_REGISTER.  */
+         for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+           if (REG_NOTE_KIND (note) == REG_CFA_RESTORE
+               || REG_NOTE_KIND (note) == REG_CFA_REGISTER)
+             {
+               rtx *x = &XEXP (note, 0);
+               if (!*x)
+                 x = &PATTERN (insn);
+               if (GET_CODE (*x) == PARALLEL)
+                 x = &XVECEXP (*x, 0, 0);
+               if (GET_CODE (*x) == SET)
+                 x = &SET_DEST (*x);
+               scan_rtx (insn, x, NO_REGS, mark_all_read, OP_IN);
+             }
        }
-      else if (DEBUG_INSN_P (insn)
+      else if (DEBUG_BIND_INSN_P (insn)
               && !VAR_LOC_UNKNOWN_P (INSN_VAR_LOCATION_LOC (insn)))
        {
          scan_rtx (insn, &INSN_VAR_LOCATION_LOC (insn),