[26/46] Make more use of dyn_cast in tree-vect*
[gcc.git] / gcc / fwprop.c
index a500e18264c1b82399c931ca998d060e69c40ebf..0fca0f1edbc24104c27bf20f8e641307d921f16d 100644 (file)
@@ -1,5 +1,5 @@
 /* RTL-based forward propagation pass for GNU compiler.
-   Copyright (C) 2005-2015 Free Software Foundation, Inc.
+   Copyright (C) 2005-2018 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
@@ -208,11 +216,11 @@ class single_def_use_dom_walker : public dom_walker
 public:
   single_def_use_dom_walker (cdi_direction direction)
     : dom_walker (direction) {}
-  virtual void before_dom_children (basic_block);
+  virtual edge before_dom_children (basic_block);
   virtual void after_dom_children (basic_block);
 };
 
-void
+edge
 single_def_use_dom_walker::before_dom_children (basic_block bb)
 {
   int bb_index = bb->index;
@@ -245,6 +253,8 @@ single_def_use_dom_walker::before_dom_children (basic_block bb)
 
   process_uses (df_get_artificial_uses (bb_index), 0);
   process_defs (df_get_artificial_defs (bb_index), 0);
+
+  return NULL;
 }
 
 /* Pop the definitions created in this basic block when leaving its
@@ -347,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));
          }
 
@@ -617,6 +627,15 @@ propagate_rtx_1 (rtx *px, rtx old_rtx, rtx new_rtx, int flags)
 
   *px = tem;
 
+  /* Allow replacements that simplify operations on a vector or complex
+     value to a component.  The most prominent case is
+     (subreg ([vec_]concat ...)).   */
+  if (REG_P (tem) && !HARD_REGISTER_P (tem)
+      && (VECTOR_MODE_P (GET_MODE (new_rtx))
+         || COMPLEX_MODE_P (GET_MODE (new_rtx)))
+      && GET_MODE (tem) == GET_MODE_INNER (GET_MODE (new_rtx)))
+    return true;
+
   /* The replacement we made so far is valid, if all of the recursive
      replacements were valid, or we could simplify everything to
      a constant.  */
@@ -661,8 +680,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 (mode, GET_MODE (SUBREG_REG (new_rtx)))))
     flags |= PR_CAN_APPEAR;
   if (!varying_mem_p (new_rtx))
     flags |= PR_HANDLE_MEM;
@@ -893,7 +911,8 @@ update_uses (df_ref use)
       if (DF_REF_ID (use) >= (int) use_def_ref.length ())
         use_def_ref.safe_grow_cleared (DF_REF_ID (use) + 1);
 
-      gcc_checking_assert (sparseset_bit_p (active_defs_check, regno));
+      if (flag_checking)
+       gcc_assert (sparseset_bit_p (active_defs_check, regno));
       use_def_ref[DF_REF_ID (use)] = active_defs[regno];
     }
 }
@@ -996,10 +1015,27 @@ try_fwprop_subst (df_ref use, rtx *loc, rtx new_rtx, rtx_insn *def_insn,
         making a new one if one does not already exist.  */
       if (set_reg_equal)
        {
-         if (dump_file)
-           fprintf (dump_file, " Setting REG_EQUAL note\n");
+         /* If there are any paradoxical SUBREGs, don't add REG_EQUAL note,
+            because the bits in there can be anything and so might not
+            match the REG_EQUAL note content.  See PR70574.  */
+         subrtx_var_iterator::array_type array;
+         FOR_EACH_SUBRTX_VAR (iter, array, *loc, NONCONST)
+           {
+             rtx x = *iter;
+             if (SUBREG_P (x) && paradoxical_subreg_p (x))
+               {
+                 set_reg_equal = false;
+                 break;
+               }
+           }
 
-         note = set_unique_reg_note (insn, REG_EQUAL, copy_rtx (new_rtx));
+         if (set_reg_equal)
+           {
+             if (dump_file)
+               fprintf (dump_file, " Setting REG_EQUAL note\n");
+
+             note = set_unique_reg_note (insn, REG_EQUAL, copy_rtx (new_rtx));
+           }
        }
     }
 
@@ -1021,9 +1057,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)
@@ -1061,6 +1095,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);
@@ -1068,9 +1103,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
@@ -1104,17 +1137,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),
@@ -1228,7 +1263,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.  */
@@ -1297,14 +1332,19 @@ forward_propagate_and_simplify (df_ref use, rtx_insn *def_insn, rtx def_set)
         that isn't mentioned in USE_SET, as the note would be invalid
         otherwise.  We also don't want to install a note if we are merely
         propagating a pseudo since verifying that this pseudo isn't dead
-        is a pain; moreover such a note won't help anything.  */
+        is a pain; moreover such a note won't help anything.
+        If the use is a paradoxical subreg, make sure we don't add a
+        REG_EQUAL note for it, because it is not equivalent, it is one
+        possible value for it, but we can't rely on it holding that value.
+        See PR70574.  */
       set_reg_equal = (note == NULL_RTX
                       && REG_P (SET_DEST (use_set))
                       && !REG_P (src)
                       && !(GET_CODE (src) == SUBREG
                            && REG_P (SUBREG_REG (src)))
                       && !reg_mentioned_p (SET_DEST (use_set),
-                                           SET_SRC (use_set)));
+                                           SET_SRC (use_set))
+                      && !paradoxical_subreg_p (DF_REF_REG (use)));
     }
 
   if (GET_MODE (*loc) == VOIDmode)
@@ -1374,6 +1414,8 @@ forward_propagate_into (df_ref use)
   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)))
@@ -1401,6 +1443,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
@@ -1436,7 +1480,6 @@ static unsigned int
 fwprop (void)
 {
   unsigned i;
-  bool need_cleanup = false;
 
   fwprop_init ();
 
@@ -1448,18 +1491,19 @@ 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)
-         need_cleanup |= forward_propagate_into (use);
+         forward_propagate_into (use);
     }
 
   fwprop_done ();
-  if (need_cleanup)
-    cleanup_cfg (0);
   return 0;
 }
 
@@ -1503,7 +1547,6 @@ static unsigned int
 fwprop_addr (void)
 {
   unsigned i;
-  bool need_cleanup = false;
 
   fwprop_init ();
 
@@ -1511,19 +1554,19 @@ fwprop_addr (void)
      end, and we'll go through them as well.  */
   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)
-         need_cleanup |= forward_propagate_into (use);
+         forward_propagate_into (use);
     }
 
   fwprop_done ();
-
-  if (need_cleanup)
-    cleanup_cfg (0);
   return 0;
 }