This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RE: Constant folding and Constant propagation


Hi Jean,

> Do you have a link to that patch? So that I can see if it applies for
me ?

See patch below. I put in some comments to try and explain what I have
attempted to do.

The hash SET generation, to track potential candidates in replacing a
register USE, needed some tweaking. This function was not tracking
register copies if the associated INSN had a NOTE attached that
associated the register with a constant. Also, only the last register
or constant in an assignment chain was being added to the hash SET.
It may be profitable to have a closer register copy in the assignment
chain as a potential replacement.

Before the actual replacing operation, the cost of temporary replacement
is determined using rtx_cost. A cost cannot be reliably formed if we
come
across jump INSNs because they may alter jumps or successors. The
default
replacement is used in this case.

Rahul


Index: gcse.c
===================================================================
--- gcse.c	(revision 141156)
+++ gcse.c	(working copy)
@@ -520,7 +520,7 @@
 static void record_set_info (rtx, const_rtx, void *);
 static void compute_sets (void);
 static void hash_scan_insn (rtx, struct hash_table *, int);
-static void hash_scan_set (rtx, rtx, struct hash_table *);
+static void hash_scan_set (rtx, rtx, struct hash_table *, bool);
 static void hash_scan_clobber (rtx, rtx, struct hash_table *);
 static void hash_scan_call (rtx, rtx, struct hash_table *);
 static int want_to_gcse_p (rtx);
@@ -560,7 +560,7 @@
 static void compute_cprop_data (void);
 static void find_used_regs (rtx *, void *);
 static int try_replace_reg (rtx, rtx, rtx);
-static struct expr *find_avail_set (int, rtx);
+static struct expr *find_avail_set (int, rtx, bool);
 static int cprop_jump (basic_block, rtx, rtx, rtx, rtx);
 static void mems_conflict_for_gcse_p (rtx, const_rtx, void *);
 static int load_killed_in_block_p (const_basic_block, int, const_rtx,
int);
@@ -1671,11 +1671,11 @@
    expression one).  */
 
 static void
-hash_scan_set (rtx pat, rtx insn, struct hash_table *table)
+hash_scan_set (rtx pat, rtx insn, struct hash_table *table, bool
use_note)
 {
   rtx src = SET_SRC (pat);
   rtx dest = SET_DEST (pat);
-  rtx note;
+  rtx note = NULL_RTX;
 
   if (GET_CODE (src) == CALL)
     hash_scan_call (src, insn, table);
@@ -1685,16 +1685,21 @@
       unsigned int regno = REGNO (dest);
       rtx tmp;
 
-      /* See if a REG_NOTE shows this equivalent to a simpler
expression.
-	 This allows us to do a single GCSE pass and still eliminate
-	 redundant constants, addresses or other expressions that are
-	 constructed with multiple instructions.  */
-      note = find_reg_equal_equiv_note (insn);
-      if (note != 0
-	  && (table->set_p
-	      ? gcse_constant_p (XEXP (note, 0))
-	      : want_to_gcse_p (XEXP (note, 0))))
-	src = XEXP (note, 0), pat = gen_rtx_SET (VOIDmode, dest, src);
+      /* Do not substitute insn SET_SRC for note if caller uses
+         uses use_note = false. */
+      if (use_note)
+        {
+	  /* See if a REG_NOTE shows this equivalent to a simpler
expression.
+	     This allows us to do a single GCSE pass and still eliminate
+	     redundant constants, addresses or other expressions that
are
+	     constructed with multiple instructions.  */
+	  note = find_reg_equal_equiv_note (insn);
+	  if (note != 0
+	      && (table->set_p
+		  ? gcse_constant_p (XEXP (note, 0))
+		  : want_to_gcse_p (XEXP (note, 0))))
+	    src = XEXP (note, 0), pat = gen_rtx_SET (VOIDmode, dest,
src);
+	}
 
       /* Only record sets of pseudo-regs in the hash table.  */
       if (! table->set_p
@@ -1835,14 +1840,30 @@
      what's been modified.  */
 
   if (GET_CODE (pat) == SET)
-    hash_scan_set (pat, insn, table);
+    {
+      /* If we're hashing SETs for constant/copy propagation
+         also hash a SET ignoring any insn notes. */
+      if (table->set_p)
+        {
+          hash_scan_set (pat, insn, table, false);
+	}
+      hash_scan_set (pat, insn, table, true);
+    }
   else if (GET_CODE (pat) == PARALLEL)
     for (i = 0; i < XVECLEN (pat, 0); i++)
       {
 	rtx x = XVECEXP (pat, 0, i);
 
 	if (GET_CODE (x) == SET)
-	  hash_scan_set (x, insn, table);
+	  {
+	    /* If we're hashing SETs for constant/copy propagation
+	       also hash a SET ignoring any insn notes. */
+	    if (table->set_p)
+	      {
+	        hash_scan_set (x, insn, table, false);
+	      }
+	    hash_scan_set (x, insn, table, true);
+	  }
 	else if (GET_CODE (x) == CLOBBER)
 	  hash_scan_clobber (x, insn, table);
 	else if (GET_CODE (x) == CALL)
@@ -2071,7 +2092,7 @@
       if (table->set_p
 	  && implicit_sets[current_bb->index] != NULL_RTX)
 	hash_scan_set (implicit_sets[current_bb->index],
-		       BB_HEAD (current_bb), table);
+		       BB_HEAD (current_bb), table, true);
 
       /* The next pass builds the hash table.  */
       in_libcall_block = 0;
@@ -2701,7 +2722,7 @@
    NULL no such set is found.  */
 
 static struct expr *
-find_avail_set (int regno, rtx insn)
+find_avail_set (int regno, rtx insn, bool follow_chain)
 {
   /* SET1 contains the last set found that can be returned to the
caller for
      use in a substitution.  */
@@ -2716,7 +2737,7 @@
 
      This can not 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)
+  do
     {
       rtx src;
       struct expr *set = lookup_set (regno, &set_hash_table);
@@ -2758,6 +2779,7 @@
 	 and see if we have an available copy into SRC.  */
       regno = REGNO (src);
     }
+  while (follow_chain);
 
   /* SET1 holds the last set that was available and anticipatable at
      INSN.  */
@@ -2944,7 +2966,12 @@
       unsigned int regno = REGNO (reg_used->reg_rtx);
       rtx pat, src;
       struct expr *set;
+      int set_cost = INT_MAX;
 
+      rtx src_first;
+      struct expr *set_first;
+      int set_first_cost = INT_MAX;
+
       /* Ignore registers created by GCSE.
 	 We do this because ...  */
       if (regno >= max_gcse_regno)
@@ -2957,10 +2984,72 @@
 
       /* Find an assignment that sets reg_used and is available
 	 at the start of the block.  */
-      set = find_avail_set (regno, insn);
+      set = find_avail_set (regno, insn, true);
       if (! set)
 	continue;
+      src = SET_SRC (set->expr);
+      
+      /* If possible, determine the cost of substituting the
+         last definition in the target insn */
+      rtx insn_set  = make_insn_raw (copy_insn (PATTERN (insn)));
+      if (NONJUMP_INSN_P (insn_set)
+	  && try_replace_reg (reg_used->reg_rtx, src, insn_set))
+	{
+	  set_cost = rtx_cost (PATTERN (insn_set),
+			       GET_CODE (PATTERN (insn_set)));
+	  
+	  /* Bias heavily for last definition if we managed to
+	     delete target insn with this substitution */
+	  if (INSN_DELETED_P (insn_set))
+	    set_cost = 0;
+	}
+	/* Might be a alter_jumps and jump insn case which we neglect
+	   in costing this option */
 
+      /* Find the first definition that sets reg_used 
+         i.e. not following the assignment chain */
+      set_first = find_avail_set (regno, insn, false);
+      
+      /* If we have a closest definition available, cost the
replacement of
+         first definition (set_first) Vs last definition (in the
assignment chain) */
+      if (set_first
+	  /* If we cannot deduce the cost of propagating constants into
+	     jump insns, go with constant propagation */
+	  && (!alter_jumps
+	      || !((any_condjump_p (insn) && onlyjump_p (insn))
+		   || (NEXT_INSN (insn) && any_condjump_p (NEXT_INSN
(insn))
+		       && onlyjump_p (NEXT_INSN (insn))))))
+        {
+	  src_first = SET_SRC (set_first->expr);
+	  
+	  if (REG_P (src_first)
+	      && REGNO (src_first) >= FIRST_PSEUDO_REGISTER
+	      && REGNO (src_first) != regno)
+	    {
+	      rtx insn_set_first  = make_insn_raw (copy_insn (PATTERN
(insn)));
+	      if (try_replace_reg (reg_used->reg_rtx, src_first,
insn_set_first))
+		{
+		  set_first_cost = rtx_cost (PATTERN (insn_set_first),
+				             GET_CODE (PATTERN
(insn_set_first)));
+		}
+	    }
+	    
+	  if (set_first_cost < set_cost)
+	    {
+	      set = set_first;
+	      set_cost = set_first_cost;
+
+	      if (dump_file)
+	        {
+		  fprintf (dump_file, "cprop_insn prefer  ");
+		  print_inline_rtx (dump_file, SET_SRC
(set_first->expr), 2);
+		  fprintf (dump_file, "  cost %d over  ",
set_first_cost);
+		  print_inline_rtx (dump_file, SET_SRC (set->expr), 2);
+		  fprintf (dump_file, "  cost %d\n", set_cost);
+	        }
+	    }
+	}
+      
       pat = set->expr;
       /* ??? We might be able to handle PARALLELs.  Later.  */
       gcc_assert (GET_CODE (pat) == SET);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]