diff gcc/postreload-gcse.c @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
line wrap: on
line diff
--- a/gcc/postreload-gcse.c	Thu Oct 25 07:37:49 2018 +0900
+++ b/gcc/postreload-gcse.c	Thu Feb 13 11:34:05 2020 +0900
@@ -1,5 +1,5 @@
 /* Post reload partially redundant load elimination
-   Copyright (C) 2004-2018 Free Software Foundation, Inc.
+   Copyright (C) 2004-2020 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -35,10 +35,13 @@
 #include "cfgrtl.h"
 #include "profile.h"
 #include "expr.h"
-#include "params.h"
 #include "tree-pass.h"
 #include "dbgcnt.h"
+#include "intl.h"
 #include "gcse-common.h"
+#include "gcse.h"
+#include "regs.h"
+#include "function-abi.h"
 
 /* The following code implements gcse after reload, the purpose of this
    pass is to cleanup redundant loads generated by reload and other
@@ -364,7 +367,7 @@
   int do_not_record_p;
   hashval_t hash;
   struct expr *cur_expr, **slot;
-  struct occr *avail_occr, *last_occr = NULL;
+  struct occr *avail_occr;
 
   hash = hash_expr (x, &do_not_record_p);
 
@@ -405,38 +408,22 @@
       cur_expr = *slot;
     }
 
-  /* Search for another occurrence in the same basic block.  */
+  /* Search for another occurrence in the same basic block.  We insert
+     insns blockwise from start to end, so keep appending to the
+     start of the list so we have to check only a single element.  */
   avail_occr = cur_expr->avail_occr;
-  while (avail_occr
-	 && BLOCK_FOR_INSN (avail_occr->insn) != BLOCK_FOR_INSN (insn))
-    {
-      /* If an occurrence isn't found, save a pointer to the end of
-	 the list.  */
-      last_occr = avail_occr;
-      avail_occr = avail_occr->next;
-    }
-
-  if (avail_occr)
-    /* Found another instance of the expression in the same basic block.
-       Prefer this occurrence to the currently recorded one.  We want
-       the last one in the block and the block is scanned from start
-       to end.  */
+  if (avail_occr
+      && BLOCK_FOR_INSN (avail_occr->insn) == BLOCK_FOR_INSN (insn))
     avail_occr->insn = insn;
   else
     {
       /* First occurrence of this expression in this basic block.  */
       avail_occr = (struct occr *) obstack_alloc (&occr_obstack,
 						  sizeof (struct occr));
-
-      /* First occurrence of this expression in any block?  */
-      if (cur_expr->avail_occr == NULL)
-        cur_expr->avail_occr = avail_occr;
-      else
-        last_occr->next = avail_occr;
-
       avail_occr->insn = insn;
-      avail_occr->next = NULL;
+      avail_occr->next = cur_expr->avail_occr;
       avail_occr->deleted_p = 0;
+      cur_expr->avail_occr = avail_occr;
     }
 }
 
@@ -504,7 +491,7 @@
            (long) expr_table->size (),
            (long) expr_table->elements (),
            expr_table->collisions ());
-  if (expr_table->elements () > 0)
+  if (!expr_table->is_empty ())
     {
       fprintf (file, "\n\ntable entries:\n");
       expr_table->traverse <FILE *, dump_expr_hash_table_entry> (file);
@@ -672,7 +659,7 @@
 	 It will set mems_conflict_p to nonzero if there may be a
 	 conflict between X and SETTER.  */
       mems_conflict_p = 0;
-      note_stores (PATTERN (setter), find_mem_conflicts, x);
+      note_stores (setter, find_mem_conflicts, x);
       if (mems_conflict_p)
 	return 1;
 
@@ -774,7 +761,7 @@
   rtx note;
 
   /* Find all stores and record them.  */
-  note_stores (PATTERN (insn), record_last_set_info, insn);
+  note_stores (insn, record_last_set_info, insn);
 
   /* Also record autoincremented REGs for this insn as changed.  */
   for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
@@ -785,25 +772,14 @@
   if (CALL_P (insn))
     {
       unsigned int regno;
-      rtx link, x;
       hard_reg_set_iterator hrsi;
-      EXECUTE_IF_SET_IN_HARD_REG_SET (regs_invalidated_by_call, 0, regno, hrsi)
+      /* We don't track modes of hard registers, so we need to be
+	 conservative and assume that partial kills are full kills.  */
+      HARD_REG_SET callee_clobbers
+	= insn_callee_abi (insn).full_and_partial_reg_clobbers ();
+      EXECUTE_IF_SET_IN_HARD_REG_SET (callee_clobbers, 0, regno, hrsi)
 	record_last_reg_set_info_regno (insn, regno);
 
-      for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
-	{
-	  gcc_assert (GET_CODE (XEXP (link, 0)) != CLOBBER_HIGH);
-	  if (GET_CODE (XEXP (link, 0)) == CLOBBER)
-	    {
-	      x = XEXP (XEXP (link, 0), 0);
-	      if (REG_P (x))
-		{
-		  gcc_assert (HARD_REGISTER_P (x));
-		  record_last_reg_set_info (insn, x);
-		}
-	    }
-	}
-
       if (! RTL_CONST_OR_PURE_CALL_P (insn))
 	record_last_mem_set_info (insn);
     }
@@ -995,7 +971,8 @@
   /* If we could not find an occurrence in BB, see if BB
      has a single predecessor with an occurrence that is
      transparent through BB.  */
-  if (single_pred_p (bb)
+  if (transp
+      && single_pred_p (bb)
       && bitmap_bit_p (transp[bb->index], bitmap_index)
       && (occr = get_bb_avail_insn (single_pred (bb), orig_occr, bitmap_index)))
     {
@@ -1168,10 +1145,21 @@
 
   /* Check if it's worth applying the partial redundancy elimination.  */
   if (ok_count.to_gcov_type ()
-      < GCSE_AFTER_RELOAD_PARTIAL_FRACTION * not_ok_count.to_gcov_type ())
+      < param_gcse_after_reload_partial_fraction * not_ok_count.to_gcov_type ())
     goto cleanup;
-  if (ok_count.to_gcov_type ()
-      < GCSE_AFTER_RELOAD_CRITICAL_FRACTION * critical_count.to_gcov_type ())
+
+  gcov_type threshold;
+#if (GCC_VERSION >= 5000)
+  if (__builtin_mul_overflow (param_gcse_after_reload_critical_fraction,
+			      critical_count.to_gcov_type (), &threshold))
+    threshold = profile_count::max_count;
+#else
+  threshold
+    = (param_gcse_after_reload_critical_fraction
+       * critical_count.to_gcov_type ());
+#endif
+
+  if (ok_count.to_gcov_type () < threshold)
     goto cleanup;
 
   /* Generate moves to the loaded register from where
@@ -1361,6 +1349,10 @@
 static void
 gcse_after_reload_main (rtx f ATTRIBUTE_UNUSED)
 {
+  /* Disable computing transparentness if it is too expensive.  */
+  bool do_transp
+    = !gcse_or_cprop_is_too_expensive (_("using simple load CSE after register "
+					 "allocation"));
 
   memset (&stats, 0, sizeof (stats));
 
@@ -1376,21 +1368,27 @@
   if (dump_file)
     dump_hash_table (dump_file);
 
-  if (expr_table->elements () > 0)
+  if (!expr_table->is_empty ())
     {
       /* Knowing which MEMs are transparent through a block can signifiantly
 	 increase the number of redundant loads found.  So compute transparency
 	 information for each memory expression in the hash table.  */
       df_analyze ();
-      /* This can not be part of the normal allocation routine because
-	 we have to know the number of elements in the hash table.  */
-      transp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
-				     expr_table->elements ());
-      bitmap_vector_ones (transp, last_basic_block_for_fn (cfun));
-      expr_table->traverse <FILE *, compute_expr_transp> (dump_file);
+      if (do_transp)
+	{
+	  /* This cannot be part of the normal allocation routine because
+	     we have to know the number of elements in the hash table.  */
+	  transp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
+					 expr_table->elements ());
+	  bitmap_vector_ones (transp, last_basic_block_for_fn (cfun));
+	  expr_table->traverse <FILE *, compute_expr_transp> (dump_file);
+	}
+      else
+	transp = NULL;
       eliminate_partially_redundant_loads ();
       delete_redundant_insns ();
-      sbitmap_vector_free (transp);
+      if (do_transp)
+	sbitmap_vector_free (transp);
 
       if (dump_file)
 	{