This is the mail archive of the gcc-patches@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]

Three cprop enhancements


The patch below contains three enhancements for the cprop pass.
* SYMBOL_REFs are treated like CONST_INTs.  This helps to reduce register
  pressure by generating more complex addressing modes.
* If find_avail_set finds a register-register copy, it re-tries to
  find an available set of the new register.  This can help to find more
  substitutions, e.g. if you have
    (set (reg1) (constant))
    (set (reg2) (reg1))
    (... (somehow_use (reg2)) ...)
  it would previously return the set of reg2, and now returns the set of
  reg1.
* The code to propagate constants into conditional jumps has been adapted
  to work for cc0 machines as well.

Regarding the last point; it left me wondering why exactly we expose the
cc0-setter/user pair to the compiler.  I can't think of anything the
compiler couldn't do if we just represented each such pair by exactly one
insn (i.e. a compare-and-jump insn).  Currently, we have lots of conditionals
in nearly every pass to deal with the complication that these pairs can't be
separated; there seems to be some potential for simplification here.
The only place I've found so far that really takes some advantage of this
representation is final.c, which tries to delete redundant comparisons.  This
could be made to work by splitting compare-and-jumps into the appropriate
pairs just before final.
Comments?

This patch bootstrapped almost successfully on i386-linux.  The only problem
was a crash of cc1obj while trying to compile libobjc, but that was caused
by a different problem (don't mix a bison-1.25 generated c-parse.h with a
bison-1.27 generated objc-parse.c...).
I also verified that cprop_cc0_jump does the right thing on x86 for the
example given in cprop.html (the announcement that was made when the feature
was added for non-cc0 machines).  Someone else should verify that it also
works on other cc0 machines.
  
Bernd

	* gcse.c (hash_scan_set): Treat SYMBOL_REFs like CONST_INTs.
	(find_avail_set): Follow chains of register-register copies.
	(cprop_jump): New function, broken out of cprop_insn.
	(cprop_cc0_jump): New function.
	(cprop_insn): Treat SYMBOL_REFs like CONST_INTs.
	Break out new function cprop_jump and use it.
	Also use cprop_cc0_jump for machines with CC0.
	(cprop): Don't crash if cprop_insn turned the insn into a NOTE.

Index: gcc/gcse.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/gcse.c,v
retrieving revision 1.37
diff -u -p -r1.37 gcse.c
--- gcse.c	1999/04/17 21:33:24	1.37
+++ gcse.c	1999/04/22 20:23:14
@@ -511,6 +511,11 @@ static sbitmap *rd_kill, *rd_gen, *reach
 /* for available exprs */
 static sbitmap *ae_kill, *ae_gen, *ae_in, *ae_out;
 
+/* Structure used by copy/constant propagation.  */
+struct reg_use {
+  rtx reg_rtx;
+};
+
 
 static void compute_can_copy	  PROTO ((void));
 
@@ -574,6 +579,8 @@ static void compute_cprop_data	PROTO ((v
 static void find_used_regs	    PROTO ((rtx));
 static int try_replace_reg	    PROTO ((rtx, rtx, rtx));
 static struct expr *find_avail_set    PROTO ((int, rtx));
+static int cprop_jump			PROTO((rtx, rtx, struct reg_use *, rtx));
+static int cprop_cc0_jump		PROTO((rtx, struct reg_use *, rtx));
 static int cprop_insn		 PROTO ((rtx, int));
 static int cprop		      PROTO ((int));
 static int one_cprop_pass	     PROTO ((int, int));
@@ -1865,6 +1872,7 @@ hash_scan_set (pat, insn, set_p)
 		    && can_copy_p [GET_MODE (dest)])
 		   /* ??? CONST_INT:wip */
 		   || GET_CODE (src) == CONST_INT
+		   || GET_CODE (src) == SYMBOL_REF
 		   || GET_CODE (src) == CONST_DOUBLE)
 	       /* A copy is not available if its src or dest is subsequently
 		  modified.  Here we want to search from INSN+1 on, but
@@ -3534,10 +3542,6 @@ compute_cprop_data ()
 
 /* Copy/constant propagation.  */
 
-struct reg_use {
-  rtx reg_rtx;
-};
-
 /* Maximum number of register uses in an insn that we handle.  */
 #define MAX_USES 8
 
@@ -3656,18 +3660,136 @@ find_avail_set (regno, insn)
      int regno;
      rtx insn;
 {
-  struct expr *set = lookup_set (regno, NULL_RTX);
-
-  while (set)
+  struct expr *set1 = 0;
+  for (;;)
     {
-      if (TEST_BIT (cprop_avin[BLOCK_NUM (insn)], set->bitmap_index))
-	break;
-      set = next_set (regno, set);
+      struct expr *set = lookup_set (regno, NULL_RTX);
+
+      while (set)
+	{
+	  if (TEST_BIT (cprop_avin[BLOCK_NUM (insn)], set->bitmap_index))
+	    break;
+	  set = next_set (regno, set);
+	}
+      if (set == 0)
+	return set1;
+
+      set1 = set;
+      if (GET_CODE (set1->expr) != SET
+	  || GET_CODE (SET_SRC (set1->expr)) != REG)
+	return set1;
+      regno = REGNO (SET_SRC (set1->expr));
     }
+}
+
+/* Subroutine of cprop_insn that tries to propagate constants into
+   JUMP_INSNS.  INSN must be a conditional jump; COPY is a copy of it
+   that we can use for substitutions.
+   REG_USED is the use we will try to replace, SRC is the constant we
+   will try to substitute for it.
+   Returns nonzero if a change was made.  */
+static int
+cprop_jump (insn, copy, reg_used, src)
+     rtx insn, copy;
+     struct reg_use *reg_used;
+     rtx src;
+{
+  rtx set = PATTERN (copy);
+  rtx temp;
+
+  /* Replace the register with the appropriate constant.  */
+  replace_rtx (SET_SRC (set), reg_used->reg_rtx, src);
+
+  temp = simplify_ternary_operation (GET_CODE (SET_SRC (set)),
+				     GET_MODE (SET_SRC (set)),
+				     GET_MODE (XEXP (SET_SRC (set), 0)),
+				     XEXP (SET_SRC (set), 0),
+				     XEXP (SET_SRC (set), 1),
+				     XEXP (SET_SRC (set), 2));
+
+  /* If no simplification can be made, then try the next
+     register.  */
+  if (temp == 0)
+    return 0;
+
+  SET_SRC (set) = temp;
+
+  /* That may have changed the structure of TEMP, so
+     force it to be rerecognized if it has not turned
+     into a nop or unconditional jump.  */
+		
+  INSN_CODE (copy) = -1;
+  if ((SET_DEST (set) == pc_rtx
+       && (SET_SRC (set) == pc_rtx
+	   || GET_CODE (SET_SRC (set)) == LABEL_REF))
+      || recog (PATTERN (copy), copy, NULL) >= 0)
+    {
+      /* This has either become an unconditional jump
+	 or a nop-jump.  We'd like to delete nop jumps
+	 here, but doing so confuses gcse.  So we just
+	 make the replacement and let later passes
+	 sort things out.  */
+      PATTERN (insn) = set;
+      INSN_CODE (insn) = -1;
+
+      /* One less use of the label this insn used to jump to
+	 if we turned this into a NOP jump.  */
+      if (SET_SRC (set) == pc_rtx && JUMP_LABEL (insn) != 0)
+	--LABEL_NUSES (JUMP_LABEL (insn));
+
+      /* If this has turned into an unconditional jump,
+	 then put a barrier after it so that the unreachable
+	 code will be deleted.  */
+      if (GET_CODE (SET_SRC (set)) == LABEL_REF)
+	emit_barrier_after (insn);
 
-  return set;
+      run_jump_opt_after_gcse = 1;
+
+      const_prop_count++;
+      if (gcse_file != NULL)
+	{
+	  int regno = REGNO (reg_used->reg_rtx);
+	  fprintf (gcse_file, "CONST-PROP: Replacing reg %d in insn %d with constant ",
+		   regno, INSN_UID (insn));
+	  print_rtl (gcse_file, src);
+	  fprintf (gcse_file, "\n");
+	}
+      return 1;
+    }
+  return 0;
 }
 
+#ifdef HAVE_cc0
+/* Subroutine of cprop_insn that tries to propagate constants into
+   JUMP_INSNS for machines that have CC0.  INSN is a single set that
+   stores into CC0; the insn following it is a conditional jump.
+   REG_USED is the use we will try to replace, SRC is the constant we
+   will try to substitute for it.
+   Returns nonzero if a change was made.  */
+static int
+cprop_cc0_jump (insn, reg_used, src)
+     rtx insn;
+     struct reg_use *reg_used;
+     rtx src;
+{
+  rtx jump = NEXT_INSN (insn);
+  rtx copy = copy_rtx (jump);
+  rtx set = PATTERN (copy);
+
+  /* We need to copy the source of the cc0 setter, as cprop_jump is going to
+     substitute into it.  */
+  replace_rtx (SET_SRC (set), cc0_rtx, copy_rtx (SET_SRC (PATTERN (insn))));
+  if (! cprop_jump (jump, copy, reg_used, src))
+    return 0;
+
+  /* If we succeeded, delete the cc0 setter.  */
+  PUT_CODE (insn, NOTE);
+  NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+  NOTE_SOURCE_FILE (insn) = 0;
+  return 1;
+}
+#endif
+
 /* Perform constant and copy propagation on INSN.
    The result is non-zero if a change was made.  */
 
@@ -3719,7 +3841,8 @@ cprop_insn (insn, alter_jumps)
       src = SET_SRC (pat);
 
       /* Constant propagation.  */
-      if (GET_CODE (src) == CONST_INT || GET_CODE (src) == CONST_DOUBLE)
+      if (GET_CODE (src) == CONST_INT || GET_CODE (src) == CONST_DOUBLE
+	  || GET_CODE (src) == SYMBOL_REF)
 	{
 	  /* Handle normal insns first.  */
 	  if (GET_CODE (insn) == INSN
@@ -3745,77 +3868,20 @@ cprop_insn (insn, alter_jumps)
 
 	     Right now the insn in question must look like
 
-	     (set (pc) (if_then_else ...))
-
-	     Note this does not currently handle machines which use cc0.  */
+	     (set (pc) (if_then_else ...))  */
 	  else if (alter_jumps
 		   && GET_CODE (insn) == JUMP_INSN && condjump_p (insn))
-	    {
-	      /* We want a copy of the JUMP_INSN so we can modify it
-		 in-place as needed without effecting the original.  */
-	      rtx copy = copy_rtx (insn);
-	      rtx set = PATTERN (copy);
-	      rtx temp;
-
-	      /* Replace the register with the appropriate constant.  */
-	      replace_rtx (SET_SRC (set), reg_used->reg_rtx, src);
-
-	      temp = simplify_ternary_operation (GET_CODE (SET_SRC (set)),
-						 GET_MODE (SET_SRC (set)),
-						 GET_MODE (XEXP (SET_SRC (set), 0)),
-						 XEXP (SET_SRC (set), 0),
-						 XEXP (SET_SRC (set), 1),
-						 XEXP (SET_SRC (set), 2));
-
-	      /* If no simplification can be made, then try the next
-		 register.  */
-	      if (temp)
-		SET_SRC (set) = temp;
-	      else
-		continue;
-
-	      /* That may have changed the structure of TEMP, so
-		 force it to be rerecognized if it has not turned
-		 into a nop or unconditional jump.  */
-		
-	      INSN_CODE (copy) = -1;
-	      if ((SET_DEST (set) == pc_rtx
-		   && (SET_SRC (set) == pc_rtx
-		       || GET_CODE (SET_SRC (set)) == LABEL_REF))
-		  || recog (PATTERN (copy), copy, NULL) >= 0)
-		{
-		  /* This has either become an unconditional jump
-		     or a nop-jump.  We'd like to delete nop jumps
-		     here, but doing so confuses gcse.  So we just
-		     make the replacement and let later passes
-		     sort things out.  */
-		  PATTERN (insn) = set;
-		  INSN_CODE (insn) = -1;
-
-		  /* One less use of the label this insn used to jump to
-		     if we turned this into a NOP jump.  */
-		  if (SET_SRC (set) == pc_rtx && JUMP_LABEL (insn) != 0)
-		    --LABEL_NUSES (JUMP_LABEL (insn));
-
-		  /* If this has turned into an unconditional jump,
-		     then put a barrier after it so that the unreachable
-		     code will be deleted.  */
-		  if (GET_CODE (SET_SRC (set)) == LABEL_REF)
-		    emit_barrier_after (insn);
-
-		  run_jump_opt_after_gcse = 1;
-
-		  changed = 1;
-		  const_prop_count++;
-		  if (gcse_file != NULL)
-		    {
-		      fprintf (gcse_file, "CONST-PROP: Replacing reg %d in insn %d with constant ",
-			       regno, INSN_UID (insn));
-		      print_rtl (gcse_file, src);
-		      fprintf (gcse_file, "\n");
-		    }
-		}
-	    }
+	    changed |= cprop_jump (insn, copy_rtx (insn), reg_used, src);
+#ifdef HAVE_cc0
+	  /* Similar code for machines that use a pair of CC0 setter and
+	     conditional jump insn.  */
+	  else if (alter_jumps
+		   && GET_CODE (PATTERN (insn)) == SET
+		   && SET_DEST (PATTERN (insn)) == cc0_rtx
+		   && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN
+		   && condjump_p (NEXT_INSN (insn)))
+	    changed |= cprop_cc0_jump (insn, reg_used, src);
+#endif
 	}
       else if (GET_CODE (src) == REG
 	       && REGNO (src) >= FIRST_PSEUDO_REGISTER
@@ -3878,8 +3944,10 @@ cprop (alter_jumps)
 	      changed |= cprop_insn (insn, alter_jumps);
 
 	      /* Keep track of everything modified by this insn.  */
-	      /* ??? Need to be careful w.r.t. mods done to INSN.  */
-	      mark_oprs_set (insn);
+	      /* ??? Need to be careful w.r.t. mods done to INSN.  Don't
+	         call mark_oprs_set if we turned the insn into a NOTE.  */
+	      if (GET_CODE (insn) != NOTE)
+		mark_oprs_set (insn);
 	    }
 	}
     }



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