vec: add exact argument for various grow functions.
[gcc.git] / gcc / fwprop.c
index 88cfefbe1ef930c847b85aa3801a8c402930ffce..756c1d6b4055aa97028aec9efa9d14a96ee81fa3 100644 (file)
@@ -1,5 +1,5 @@
 /* RTL-based forward propagation pass for GNU compiler.
-   Copyright (C) 2005-2016 Free Software Foundation, Inc.
+   Copyright (C) 2005-2020 Free Software Foundation, Inc.
    Contributed by Paolo Bonzini and Steven Bosscher.
 
 This file is part of GCC.
@@ -26,6 +26,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "rtl.h"
 #include "predict.h"
 #include "df.h"
+#include "memmodel.h"
 #include "tm_p.h"
 #include "insn-config.h"
 #include "emit-rtl.h"
@@ -119,6 +120,13 @@ static vec<df_ref> use_def_ref;
 static vec<df_ref> reg_defs;
 static vec<df_ref> reg_defs_stack;
 
+/* The maximum number of propagations that are still allowed.  If we do
+   more propagations than originally we had uses, we must have ended up
+   in a propagation loop, as in PR79405.  Until the algorithm fwprop
+   uses can obviously not get into such loops we need a workaround like
+   this.  */
+static int propagations_left;
+
 /* The MD bitmaps are trimmed to include only live registers to cut
    memory usage on testcases like insn-recog.c.  Track live registers
    in the basic block and do not perform forward propagation if the
@@ -216,8 +224,8 @@ edge
 single_def_use_dom_walker::before_dom_children (basic_block bb)
 {
   int bb_index = bb->index;
-  struct df_md_bb_info *md_bb_info = df_md_get_bb_info (bb_index);
-  struct df_lr_bb_info *lr_bb_info = df_lr_get_bb_info (bb_index);
+  class df_md_bb_info *md_bb_info = df_md_get_bb_info (bb_index);
+  class df_lr_bb_info *lr_bb_info = df_lr_get_bb_info (bb_index);
   rtx_insn *insn;
 
   bitmap_copy (local_md, &md_bb_info->in);
@@ -284,10 +292,10 @@ build_single_def_use_links (void)
   df_maybe_reorganize_use_refs (DF_REF_ORDER_BY_INSN_WITH_NOTES);
 
   use_def_ref.create (DF_USES_TABLE_SIZE ());
-  use_def_ref.safe_grow_cleared (DF_USES_TABLE_SIZE ());
+  use_def_ref.safe_grow_cleared (DF_USES_TABLE_SIZE (), true);
 
   reg_defs.create (max_reg_num ());
-  reg_defs.safe_grow_cleared (max_reg_num ());
+  reg_defs.safe_grow_cleared (max_reg_num (), true);
 
   reg_defs_stack.create (n_basic_blocks_for_fn (cfun) * 10);
   local_md = BITMAP_ALLOC (NULL);
@@ -349,12 +357,12 @@ canonicalize_address (rtx x)
       {
       case ASHIFT:
         if (CONST_INT_P (XEXP (x, 1))
-            && INTVAL (XEXP (x, 1)) < GET_MODE_BITSIZE (GET_MODE (x))
-            && INTVAL (XEXP (x, 1)) >= 0)
+           && INTVAL (XEXP (x, 1)) < GET_MODE_UNIT_BITSIZE (GET_MODE (x))
+           && INTVAL (XEXP (x, 1)) >= 0)
          {
            HOST_WIDE_INT shift = INTVAL (XEXP (x, 1));
            PUT_CODE (x, MULT);
-           XEXP (x, 1) = gen_int_mode ((HOST_WIDE_INT) 1 << shift,
+           XEXP (x, 1) = gen_int_mode (HOST_WIDE_INT_1 << shift,
                                        GET_MODE (x));
          }
 
@@ -440,6 +448,18 @@ enum {
   PR_OPTIMIZE_FOR_SPEED = 4
 };
 
+/* Check that X has a single def.  */
+
+static bool
+reg_single_def_p (rtx x)
+{
+  if (!REG_P (x))
+    return false;
+
+  int regno = REGNO (x);
+  return (DF_REG_DEF_COUNT (regno) == 1
+         && !bitmap_bit_p (DF_LR_OUT (ENTRY_BLOCK_PTR_FOR_FN (cfun)), regno));
+}
 
 /* Replace all occurrences of OLD in *PX with NEW and try to simplify the
    resulting expression.  Replace *PX with a new RTL expression if an
@@ -539,6 +559,54 @@ propagate_rtx_1 (rtx *px, rtx old_rtx, rtx new_rtx, int flags)
          tem = simplify_gen_subreg (mode, op0, GET_MODE (SUBREG_REG (x)),
                                     SUBREG_BYTE (x));
        }
+
+      else
+       {
+         rtvec vec;
+         rtvec newvec;
+         const char *fmt = GET_RTX_FORMAT (code);
+         rtx op;
+
+         for (int i = 0; fmt[i]; i++)
+           switch (fmt[i])
+             {
+             case 'E':
+               vec = XVEC (x, i);
+               newvec = vec;
+               for (int j = 0; j < GET_NUM_ELEM (vec); j++)
+                 {
+                   op = RTVEC_ELT (vec, j);
+                   valid_ops &= propagate_rtx_1 (&op, old_rtx, new_rtx, flags);
+                   if (op != RTVEC_ELT (vec, j))
+                     {
+                       if (newvec == vec)
+                         {
+                           newvec = shallow_copy_rtvec (vec);
+                           if (!tem)
+                             tem = shallow_copy_rtx (x);
+                           XVEC (tem, i) = newvec;
+                         }
+                       RTVEC_ELT (newvec, j) = op;
+                     }
+                 }
+               break;
+
+             case 'e':
+               if (XEXP (x, i))
+                 {
+                   op = XEXP (x, i);
+                   valid_ops &= propagate_rtx_1 (&op, old_rtx, new_rtx, flags);
+                   if (op != XEXP (x, i))
+                     {
+                       if (!tem)
+                         tem = shallow_copy_rtx (x);
+                       XEXP (tem, i) = op;
+                     }
+                 }
+               break;
+             }
+       }
+
       break;
 
     case RTX_OBJ:
@@ -672,8 +740,7 @@ propagate_rtx (rtx x, machine_mode mode, rtx old_rtx, rtx new_rtx,
       || CONSTANT_P (new_rtx)
       || (GET_CODE (new_rtx) == SUBREG
          && REG_P (SUBREG_REG (new_rtx))
-         && (GET_MODE_SIZE (mode)
-             <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (new_rtx))))))
+         && !paradoxical_subreg_p (new_rtx)))
     flags |= PR_CAN_APPEAR;
   if (!varying_mem_p (new_rtx))
     flags |= PR_HANDLE_MEM;
@@ -724,14 +791,15 @@ local_ref_killed_between_p (df_ref ref, rtx_insn *from, rtx_insn *to)
 }
 
 
-/* Check if the given DEF is available in INSN.  This would require full
-   computation of available expressions; we check only restricted conditions:
-   - if DEF is the sole definition of its register, go ahead;
-   - in the same basic block, we check for no definitions killing the
-     definition of DEF_INSN;
-   - if USE's basic block has DEF's basic block as the sole predecessor,
-     we check if the definition is killed after DEF_INSN or before
+/* Check if USE is killed between DEF_INSN and TARGET_INSN.  This would
+   require full computation of available expressions; we check only a few
+   restricted conditions:
+   - if the reg in USE has only one definition, go ahead;
+   - in the same basic block, we check for no definitions killing the use;
+   - if TARGET_INSN's basic block has DEF_INSN's basic block as its sole
+     predecessor, we check if the use is killed after DEF_INSN or before
      TARGET_INSN insn, in their respective basic blocks.  */
+
 static bool
 use_killed_between (df_ref use, rtx_insn *def_insn, rtx_insn *target_insn)
 {
@@ -755,12 +823,17 @@ use_killed_between (df_ref use, rtx_insn *def_insn, rtx_insn *target_insn)
      know that this definition reaches use, or we wouldn't be here.
      However, this is invalid for hard registers because if they are
      live at the beginning of the function it does not mean that we
-     have an uninitialized access.  */
+     have an uninitialized access.  And we have to check for the case
+     where a register may be used uninitialized in a loop as above.  */
   regno = DF_REF_REGNO (use);
   def = DF_REG_DEF_CHAIN (regno);
   if (def
       && DF_REF_NEXT_REG (def) == NULL
-      && regno >= FIRST_PSEUDO_REGISTER)
+      && regno >= FIRST_PSEUDO_REGISTER
+      && (BLOCK_FOR_INSN (DF_REF_INSN (def)) == def_bb
+         ? DF_INSN_LUID (DF_REF_INSN (def)) < DF_INSN_LUID (def_insn)
+         : dominated_by_p (CDI_DOMINATORS,
+                           def_bb, BLOCK_FOR_INSN (DF_REF_INSN (def)))))
     return false;
 
   /* Check locally if we are in the same basic block.  */
@@ -902,7 +975,7 @@ update_uses (df_ref use)
 
       /* Set up the use-def chain.  */
       if (DF_REF_ID (use) >= (int) use_def_ref.length ())
-        use_def_ref.safe_grow_cleared (DF_REF_ID (use) + 1);
+       use_def_ref.safe_grow_cleared (DF_REF_ID (use) + 1, true);
 
       if (flag_checking)
        gcc_assert (sparseset_bit_p (active_defs_check, regno));
@@ -1050,9 +1123,7 @@ free_load_extend (rtx src, rtx_insn *insn)
   df_ref def, use;
 
   reg = XEXP (src, 0);
-#ifdef LOAD_EXTEND_OP
-  if (LOAD_EXTEND_OP (GET_MODE (reg)) != GET_CODE (src))
-#endif
+  if (load_extend_op (GET_MODE (reg)) != GET_CODE (src))
     return false;
 
   FOR_EACH_INSN_USE (use, insn)
@@ -1090,6 +1161,7 @@ forward_propagate_subreg (df_ref use, rtx_insn *def_insn, rtx def_set)
   rtx use_reg = DF_REF_REG (use);
   rtx_insn *use_insn;
   rtx src;
+  scalar_int_mode int_use_mode, src_mode;
 
   /* Only consider subregs... */
   machine_mode use_mode = GET_MODE (use_reg);
@@ -1097,9 +1169,7 @@ forward_propagate_subreg (df_ref use, rtx_insn *def_insn, rtx def_set)
       || !REG_P (SET_DEST (def_set)))
     return false;
 
-  /* If this is a paradoxical SUBREG...  */
-  if (GET_MODE_SIZE (use_mode)
-      > GET_MODE_SIZE (GET_MODE (SUBREG_REG (use_reg))))
+  if (paradoxical_subreg_p (use_reg))
     {
       /* If this is a paradoxical SUBREG, we have no idea what value the
         extra bits would have.  However, if the operand is equivalent to
@@ -1133,17 +1203,19 @@ forward_propagate_subreg (df_ref use, rtx_insn *def_insn, rtx def_set)
      definition of Y or, failing that, allow A to be deleted after
      reload through register tying.  Introducing more uses of Y
      prevents both optimisations.  */
-  else if (subreg_lowpart_p (use_reg))
+  else if (is_a <scalar_int_mode> (use_mode, &int_use_mode)
+          && subreg_lowpart_p (use_reg))
     {
       use_insn = DF_REF_INSN (use);
       src = SET_SRC (def_set);
       if ((GET_CODE (src) == ZERO_EXTEND
           || GET_CODE (src) == SIGN_EXTEND)
+         && is_a <scalar_int_mode> (GET_MODE (src), &src_mode)
          && REG_P (XEXP (src, 0))
          && REGNO (XEXP (src, 0)) >= FIRST_PSEUDO_REGISTER
          && GET_MODE (XEXP (src, 0)) == use_mode
          && !free_load_extend (src, def_insn)
-         && (targetm.mode_rep_extended (use_mode, GET_MODE (src))
+         && (targetm.mode_rep_extended (int_use_mode, src_mode)
              != (int) GET_CODE (src))
          && all_uses_available_at (def_insn, use_insn))
        return try_fwprop_subst (use, DF_REF_LOC (use), XEXP (src, 0),
@@ -1257,7 +1329,7 @@ forward_propagate_and_simplify (df_ref use, rtx_insn *def_insn, rtx def_set)
   reg = DF_REF_REG (use);
   if (GET_CODE (reg) == SUBREG && GET_CODE (SET_DEST (def_set)) == SUBREG)
     {
-      if (SUBREG_BYTE (SET_DEST (def_set)) != SUBREG_BYTE (reg))
+      if (maybe_ne (SUBREG_BYTE (SET_DEST (def_set)), SUBREG_BYTE (reg)))
        return false;
     }
   /* Check if the def had a subreg, but the use has the whole reg.  */
@@ -1358,10 +1430,11 @@ forward_propagate_and_simplify (df_ref use, rtx_insn *def_insn, rtx def_set)
 
 /* Given a use USE of an insn, if it has a single reaching
    definition, try to forward propagate it into that insn.
-   Return true if cfg cleanup will be needed.  */
+   Return true if cfg cleanup will be needed.
+   REG_PROP_ONLY is true if we should only propagate register copies.  */
 
 static bool
-forward_propagate_into (df_ref use)
+forward_propagate_into (df_ref use, bool reg_prop_only = false)
 {
   df_ref def;
   rtx_insn *def_insn, *use_insn;
@@ -1382,10 +1455,6 @@ forward_propagate_into (df_ref use)
   if (DF_REF_IS_ARTIFICIAL (def))
     return false;
 
-  /* Do not propagate loop invariant definitions inside the loop.  */
-  if (DF_REF_BB (def)->loop_father != DF_REF_BB (use)->loop_father)
-    return false;
-
   /* Check if the use is still present in the insn!  */
   use_insn = DF_REF_INSN (use);
   if (DF_REF_FLAGS (use) & DF_REF_IN_NOTE)
@@ -1403,11 +1472,26 @@ forward_propagate_into (df_ref use)
   if (!def_set)
     return false;
 
+  if (reg_prop_only
+      && (!reg_single_def_p (SET_SRC (def_set))
+         || !reg_single_def_p (SET_DEST (def_set))))
+    return false;
+
+  /* Allow propagations into a loop only for reg-to-reg copies, since
+     replacing one register by another shouldn't increase the cost.  */
+
+  if (DF_REF_BB (def)->loop_father != DF_REF_BB (use)->loop_father
+      && (!reg_single_def_p (SET_SRC (def_set))
+         || !reg_single_def_p (SET_DEST (def_set))))
+    return false;
+
   /* Only try one kind of propagation.  If two are possible, we'll
      do it on the following iterations.  */
   if (forward_propagate_and_simplify (use, def_insn, def_set)
       || forward_propagate_subreg (use, def_insn, def_set))
     {
+      propagations_left--;
+
       if (cfun->can_throw_non_call_exceptions
          && find_reg_note (use_insn, REG_EH_REGION, NULL_RTX)
          && purge_dead_edges (DF_REF_BB (use)))
@@ -1435,6 +1519,8 @@ fwprop_init (void)
   active_defs = XNEWVEC (df_ref, max_reg_num ());
   if (flag_checking)
     active_defs_check = sparseset_alloc (max_reg_num ());
+
+  propagations_left = DF_USES_TABLE_SIZE ();
 }
 
 static void
@@ -1467,7 +1553,7 @@ gate_fwprop (void)
 }
 
 static unsigned int
-fwprop (void)
+fwprop (bool fwprop_addr_p)
 {
   unsigned i;
 
@@ -1481,13 +1567,21 @@ fwprop (void)
 
   for (i = 0; i < DF_USES_TABLE_SIZE (); i++)
     {
+      if (!propagations_left)
+       break;
+
       df_ref use = DF_USES_GET (i);
       if (use)
-       if (DF_REF_TYPE (use) == DF_REF_REG_USE
-           || DF_REF_BB (use)->loop_father == NULL
-           /* The outer most loop is not really a loop.  */
-           || loop_outer (DF_REF_BB (use)->loop_father) == NULL)
-         forward_propagate_into (use);
+       {
+         if (DF_REF_TYPE (use) == DF_REF_REG_USE
+             || DF_REF_BB (use)->loop_father == NULL
+             /* The outer most loop is not really a loop.  */
+             || loop_outer (DF_REF_BB (use)->loop_father) == NULL)
+           forward_propagate_into (use, fwprop_addr_p);
+
+         else if (fwprop_addr_p)
+           forward_propagate_into (use, false);
+       }
     }
 
   fwprop_done ();
@@ -1518,7 +1612,7 @@ public:
 
   /* opt_pass methods: */
   virtual bool gate (function *) { return gate_fwprop (); }
-  virtual unsigned int execute (function *) { return fwprop (); }
+  virtual unsigned int execute (function *) { return fwprop (false); }
 
 }; // class pass_rtl_fwprop
 
@@ -1530,30 +1624,6 @@ make_pass_rtl_fwprop (gcc::context *ctxt)
   return new pass_rtl_fwprop (ctxt);
 }
 
-static unsigned int
-fwprop_addr (void)
-{
-  unsigned i;
-
-  fwprop_init ();
-
-  /* Go through all the uses.  df_uses_create will create new ones at the
-     end, and we'll go through them as well.  */
-  for (i = 0; i < DF_USES_TABLE_SIZE (); i++)
-    {
-      df_ref use = DF_USES_GET (i);
-      if (use)
-       if (DF_REF_TYPE (use) != DF_REF_REG_USE
-           && DF_REF_BB (use)->loop_father != NULL
-           /* The outer most loop is not really a loop.  */
-           && loop_outer (DF_REF_BB (use)->loop_father) != NULL)
-         forward_propagate_into (use);
-    }
-
-  fwprop_done ();
-  return 0;
-}
-
 namespace {
 
 const pass_data pass_data_rtl_fwprop_addr =
@@ -1578,7 +1648,7 @@ public:
 
   /* opt_pass methods: */
   virtual bool gate (function *) { return gate_fwprop (); }
-  virtual unsigned int execute (function *) { return fwprop_addr (); }
+  virtual unsigned int execute (function *) { return fwprop (true); }
 
 }; // class pass_rtl_fwprop_addr