]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/cprop.c
[Ada] Fix documentation for GNAT.Command_Line.Exit_From_Command_Line
[thirdparty/gcc.git] / gcc / cprop.c
index a0e7989deddb711283463d3027a8c18e1e905a22..65c0130cc07a1327ccae43a718d82485c4bd28b8 100644 (file)
@@ -1,5 +1,5 @@
 /* Global constant/copy propagation for RTL.
-   Copyright (C) 1997-2015 Free Software Foundation, Inc.
+   Copyright (C) 1997-2019 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -20,53 +20,27 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
-#include "diagnostic-core.h"
-#include "toplev.h"
+#include "backend.h"
 #include "rtl.h"
-#include "hash-set.h"
-#include "vec.h"
-#include "input.h"
-#include "alias.h"
-#include "symtab.h"
-#include "inchash.h"
-#include "tree.h"
-#include "tm_p.h"
-#include "regs.h"
-#include "hard-reg-set.h"
-#include "flags.h"
+#include "cfghooks.h"
+#include "df.h"
 #include "insn-config.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
 #include "recog.h"
-#include "predict.h"
-#include "hashtab.h"
-#include "function.h"
-#include "dominance.h"
-#include "cfg.h"
+#include "diagnostic-core.h"
+#include "toplev.h"
 #include "cfgrtl.h"
 #include "cfganal.h"
 #include "lcm.h"
 #include "cfgcleanup.h"
-#include "basic-block.h"
-#include "statistics.h"
-#include "expmed.h"
-#include "dojump.h"
-#include "explow.h"
-#include "calls.h"
-#include "emit-rtl.h"
-#include "varasm.h"
-#include "stmt.h"
-#include "expr.h"
-#include "except.h"
 #include "params.h"
-#include "alloc-pool.h"
 #include "cselib.h"
 #include "intl.h"
-#include "obstack.h"
 #include "tree-pass.h"
-#include "df.h"
 #include "dbgcnt.h"
-#include "target.h"
 #include "cfgloop.h"
+#include "gcse.h"
 
 \f
 /* An obstack for our working variables.  */
@@ -84,8 +58,6 @@ struct cprop_occr
   rtx_insn *insn;
 };
 
-typedef struct cprop_occr *occr_t;
-
 /* Hash table entry for assignment expressions.  */
 
 struct cprop_expr
@@ -765,11 +737,12 @@ try_replace_reg (rtx from, rtx to, rtx_insn *insn)
   bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn));
   int old_cost = set ? set_rtx_cost (set, speed) : 0;
 
-  if ((note != 0
-      && REG_NOTE_KIND (note) == REG_EQUAL
-      && (GET_CODE (XEXP (note, 0)) == CONST
-         || CONSTANT_P (XEXP (note, 0))))
-      || (set && CONSTANT_P (SET_SRC (set))))
+  if (!set
+      || CONSTANT_P (SET_SRC (set))
+      || (note != 0
+         && REG_NOTE_KIND (note) == REG_EQUAL
+         && (GET_CODE (XEXP (note, 0)) == CONST
+             || CONSTANT_P (XEXP (note, 0)))))
     check_rtx_costs = false;
 
   /* Usually we substitute easy stuff, so we won't copy everything.
@@ -785,7 +758,7 @@ try_replace_reg (rtx from, rtx to, rtx_insn *insn)
 
   if (check_rtx_costs
       && CONSTANT_P (to)
-      && (set_rtx_cost (set, speed) > old_cost))
+      && set_rtx_cost (set, speed) > old_cost)
     {
       cancel_changes (0);
       return false;
@@ -866,7 +839,7 @@ find_avail_set (int regno, rtx_insn *insn, struct cprop_expr *set_ret[2])
        (set (reg X) (reg Y))
        (set (reg Y) (reg X))
 
-     This can not happen since the set of (reg Y) would have killed the
+     This cannot happen since the set of (reg Y) would have killed the
      set of (reg X) making it unavailable at the start of this block.  */
   while (1)
     {
@@ -999,7 +972,7 @@ cprop_jump (basic_block bb, rtx_insn *setcc, rtx_insn *jump, rtx from, rtx src)
   if (dump_file != NULL)
     {
       fprintf (dump_file,
-              "GLOBAL CONST-PROP: Replacing reg %d in jump_insn %d with"
+              "GLOBAL CONST-PROP: Replacing reg %d in jump_insn %d with "
               "constant ", REGNO (from), INSN_UID (jump));
       print_rtl (dump_file, src);
       fprintf (dump_file, "\n");
@@ -1188,9 +1161,7 @@ local_cprop_find_used_regs (rtx *xptr, void *data)
       return;
 
     case SUBREG:
-      /* Setting a subreg of a register larger than word_mode leaves
-        the non-written words unchanged.  */
-      if (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) > BITS_PER_WORD)
+      if (read_modify_subreg_p (x))
        return;
       break;
 
@@ -1277,6 +1248,8 @@ local_cprop_pass (void)
   bool changed = false;
   unsigned i;
 
+  auto_vec<rtx_insn *> uncond_traps;
+
   cselib_init (0);
   FOR_EACH_BB_FN (bb, cfun)
     {
@@ -1284,6 +1257,9 @@ local_cprop_pass (void)
        {
          if (INSN_P (insn))
            {
+             bool was_uncond_trap
+               = (GET_CODE (PATTERN (insn)) == TRAP_IF
+                  && XEXP (PATTERN (insn), 0) == const1_rtx);
              rtx note = find_reg_equal_equiv_note (insn);
              do
                {
@@ -1302,6 +1278,13 @@ local_cprop_pass (void)
                          break;
                        }
                    }
+                 if (!was_uncond_trap
+                     && GET_CODE (PATTERN (insn)) == TRAP_IF
+                     && XEXP (PATTERN (insn), 0) == const1_rtx)
+                   {
+                     uncond_traps.safe_push (insn);
+                     break;
+                   }
                  if (insn->deleted ())
                    break;
                }
@@ -1316,6 +1299,14 @@ local_cprop_pass (void)
 
   cselib_finish ();
 
+  while (!uncond_traps.is_empty ())
+    {
+      rtx_insn *insn = uncond_traps.pop ();
+      basic_block to_split = BLOCK_FOR_INSN (insn);
+      remove_edge (split_block (to_split, insn));
+      emit_barrier_after_bb (to_split);
+    }
+
   return changed;
 }
 
@@ -1365,13 +1356,9 @@ implicit_set_cond_p (const_rtx cond)
         the optimization can't be performed.  */
       /* ??? The complex and vector checks are not implemented yet.  We just
         always return zero for them.  */
-      if (CONST_DOUBLE_AS_FLOAT_P (cst))
-       {
-         REAL_VALUE_TYPE d;
-         REAL_VALUE_FROM_CONST_DOUBLE (d, cst);
-         if (REAL_VALUES_EQUAL (d, dconst0))
-           return 0;
-       }
+      if (CONST_DOUBLE_AS_FLOAT_P (cst)
+         && real_equal (CONST_DOUBLE_REAL_VALUE (cst), &dconst0))
+       return 0;
       else
        return 0;
     }
@@ -1710,7 +1697,6 @@ bypass_conditional_jumps (void)
   if (ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb == EXIT_BLOCK_PTR_FOR_FN (cfun))
     return 0;
 
-  bypass_last_basic_block = last_basic_block_for_fn (cfun);
   mark_dfs_back_edges ();
 
   changed = 0;
@@ -1757,47 +1743,6 @@ bypass_conditional_jumps (void)
   return changed;
 }
 \f
-/* Return true if the graph is too expensive to optimize.  PASS is the
-   optimization about to be performed.  */
-
-static bool
-is_too_expensive (const char *pass)
-{
-  /* Trying to perform global optimizations on flow graphs which have
-     a high connectivity will take a long time and is unlikely to be
-     particularly useful.
-
-     In normal circumstances a cfg should have about twice as many
-     edges as blocks.  But we do not want to punish small functions
-     which have a couple switch statements.  Rather than simply
-     threshold the number of blocks, uses something with a more
-     graceful degradation.  */
-  if (n_edges_for_fn (cfun) > 20000 + n_basic_blocks_for_fn (cfun) * 4)
-    {
-      warning (OPT_Wdisabled_optimization,
-              "%s: %d basic blocks and %d edges/basic block",
-              pass, n_basic_blocks_for_fn (cfun),
-              n_edges_for_fn (cfun) / n_basic_blocks_for_fn (cfun));
-
-      return true;
-    }
-
-  /* If allocating memory for the cprop bitmap would take up too much
-     storage it's better just to disable the optimization.  */
-  if ((n_basic_blocks_for_fn (cfun)
-       * SBITMAP_SET_SIZE (max_reg_num ())
-       * sizeof (SBITMAP_ELT_TYPE)) > MAX_GCSE_MEMORY)
-    {
-      warning (OPT_Wdisabled_optimization,
-              "%s: %d basic blocks and %d registers",
-              pass, n_basic_blocks_for_fn (cfun), max_reg_num ());
-
-      return true;
-    }
-
-  return false;
-}
-\f
 /* Main function for the CPROP pass.  */
 
 static int
@@ -1808,7 +1753,7 @@ one_cprop_pass (void)
 
   /* Return if there's nothing to do, or it is too expensive.  */
   if (n_basic_blocks_for_fn (cfun) <= NUM_FIXED_BLOCKS + 1
-      || is_too_expensive (_ ("const/copy propagation disabled")))
+      || gcse_or_cprop_is_too_expensive (_ ("const/copy propagation disabled")))
     return 0;
 
   global_const_prop_count = local_const_prop_count = 0;
@@ -1868,7 +1813,7 @@ one_cprop_pass (void)
   if (set_hash_table.n_elems > 0)
     {
       basic_block bb;
-      rtx_insn *insn;
+      auto_vec<rtx_insn *> uncond_traps;
 
       alloc_cprop_mem (last_basic_block_for_fn (cfun),
                       set_hash_table.n_elems);
@@ -1884,6 +1829,9 @@ one_cprop_pass (void)
                      EXIT_BLOCK_PTR_FOR_FN (cfun),
                      next_bb)
        {
+         bool seen_uncond_trap = false;
+         rtx_insn *insn;
+
          /* Reset tables used to keep track of what's still valid [since
             the start of the block].  */
          reset_opr_set_tables ();
@@ -1891,6 +1839,10 @@ one_cprop_pass (void)
          FOR_BB_INSNS (bb, insn)
            if (INSN_P (insn))
              {
+               bool was_uncond_trap
+                 = (GET_CODE (PATTERN (insn)) == TRAP_IF
+                    && XEXP (PATTERN (insn), 0) == const1_rtx);
+
                changed |= cprop_insn (insn);
 
                /* Keep track of everything modified by this insn.  */
@@ -1899,9 +1851,40 @@ one_cprop_pass (void)
                       insn into a NOTE, or deleted the insn.  */
                if (! NOTE_P (insn) && ! insn->deleted ())
                  mark_oprs_set (insn);
+
+               if (!was_uncond_trap
+                   && GET_CODE (PATTERN (insn)) == TRAP_IF
+                   && XEXP (PATTERN (insn), 0) == const1_rtx)
+                 {
+                   /* If we have already seen an unconditional trap
+                      earlier, the rest of the bb is going to be removed
+                      as unreachable.  Just turn it into a note, so that
+                      RTL verification doesn't complain about it before
+                      it is finally removed.  */
+                   if (seen_uncond_trap)
+                     set_insn_deleted (insn);
+                   else
+                     {
+                       seen_uncond_trap = true;
+                       uncond_traps.safe_push (insn);
+                     }
+                 }
              }
        }
 
+      /* Make sure bypass_conditional_jumps will ignore not just its new
+        basic blocks, but also the ones after unconditional traps (those are
+        unreachable and will be eventually removed as such).  */
+      bypass_last_basic_block = last_basic_block_for_fn (cfun);
+
+      while (!uncond_traps.is_empty ())
+       {
+         rtx_insn *insn = uncond_traps.pop ();
+         basic_block to_split = BLOCK_FOR_INSN (insn);
+         remove_edge (split_block (to_split, insn));
+         emit_barrier_after_bb (to_split);
+       }
+
       changed |= bypass_conditional_jumps ();
 
       FREE_REG_SET (reg_set_bitmap);