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]

Improvement to constant propagation


Having cprop call simplify_replace_rtx allows more constants to be 
propagated.  This is further increased by looking at REG_EQUAL and
REG_EQUIV notes on insns that generate available expressions.

Tested on alphaev56.

Fri Feb 16 14:22:40 2001  Richard Kenner  <kenner@vlsi1.ultra.nyu.edu>

	* gcse.c (hash_scan_set): If cprop, see if REG_EQUAL or REG_EQUIV.
	Don't CSE a nop.
	(hash_scan_insn): Clean up calls to hash_scan_set.
	(compute_kill_rd): REGNO now unsigned.
	(try_replace_reg): Rework to use simplify_replace_rtx.
	(cprop_jump, cprop_cc0_jump): Likewise.
	(cprop_insn): Call find_reg_equal_equiv_note.
	Reflect changes to cprop_jump and cprop_cc0_jump.

*** gcse.c	2001/02/13 20:17:44	1.114
--- gcse.c	2001/02/16 13:37:16
*************** static void find_used_regs	PARAMS ((rtx)
*** 584,588 ****
  static int try_replace_reg	PARAMS ((rtx, rtx, rtx));
  static struct expr *find_avail_set PARAMS ((int, rtx));
! static int cprop_jump		PARAMS ((rtx, rtx, struct reg_use *, rtx));
  #ifdef HAVE_cc0
  static int cprop_cc0_jump	PARAMS ((rtx, struct reg_use *, rtx));
--- 584,588 ----
  static int try_replace_reg	PARAMS ((rtx, rtx, rtx));
  static struct expr *find_avail_set PARAMS ((int, rtx));
! static int cprop_jump		PARAMS ((rtx, rtx, rtx));
  #ifdef HAVE_cc0
  static int cprop_cc0_jump	PARAMS ((rtx, struct reg_use *, rtx));
*************** hash_scan_set (pat, insn, set_p)
*** 1911,1923 ****
    rtx src = SET_SRC (pat);
    rtx dest = SET_DEST (pat);
  
    if (GET_CODE (src) == CALL)
      hash_scan_call (src, insn);
  
!   if (GET_CODE (dest) == REG)
      {
!       int regno = REGNO (dest);
        rtx tmp;
  
        /* Only record sets of pseudo-regs in the hash table.  */
        if (! set_p
--- 1912,1931 ----
    rtx src = SET_SRC (pat);
    rtx dest = SET_DEST (pat);
+   rtx note;
  
    if (GET_CODE (src) == CALL)
      hash_scan_call (src, insn);
  
!   else if (GET_CODE (dest) == REG)
      {
!       unsigned int regno = REGNO (dest);
        rtx tmp;
  
+       /* If this is a single set and we are doing constant propagation,
+ 	 see if a REG_NOTE shows this equivalent to a constant.  */
+       if (set_p && (note = find_reg_equal_equiv_note (insn)) != 0
+ 	  && CONSTANT_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 (! set_p
*************** hash_scan_set (pat, insn, set_p)
*** 1926,1930 ****
  	  && can_copy_p [GET_MODE (dest)]
  	  /* Is SET_SRC something we want to gcse?  */
! 	  && want_to_gcse_p (src))
  	{
  	  /* An expression is not anticipatable if its operands are
--- 1934,1940 ----
  	  && can_copy_p [GET_MODE (dest)]
  	  /* Is SET_SRC something we want to gcse?  */
! 	  && want_to_gcse_p (src)
! 	  /* Don't CSE a nop.  */
! 	  && src != dest)
  	{
  	  /* An expression is not anticipatable if its operands are
*************** hash_scan_set (pat, insn, set_p)
*** 1943,1947 ****
  	       && ((GET_CODE (src) == REG
  		    && REGNO (src) >= FIRST_PSEUDO_REGISTER
! 		    && can_copy_p [GET_MODE (dest)])
  		   || GET_CODE (src) == CONST_INT
  		   || GET_CODE (src) == SYMBOL_REF
--- 1953,1958 ----
  	       && ((GET_CODE (src) == REG
  		    && REGNO (src) >= FIRST_PSEUDO_REGISTER
! 		    && can_copy_p [GET_MODE (dest)]
! 		    && REGNO (src) != regno)
  		   || GET_CODE (src) == CONST_INT
  		   || GET_CODE (src) == SYMBOL_REF
*************** hash_scan_insn (insn, set_p, in_libcall_
*** 1993,2005 ****
    int i;
  
    /* Pick out the sets of INSN and for other forms of instructions record
       what's been modified.  */
  
!   if (GET_CODE (pat) == SET && ! in_libcall_block)
!     {
!       /* Ignore obvious no-ops.  */
!       if (SET_SRC (pat) != SET_DEST (pat))
! 	hash_scan_set (pat, insn, set_p);
!     }
    else if (GET_CODE (pat) == PARALLEL)
      for (i = 0; i < XVECLEN (pat, 0); i++)
--- 2004,2015 ----
    int i;
  
+   if (in_libcall_block)
+     return;
+ 
    /* Pick out the sets of INSN and for other forms of instructions record
       what's been modified.  */
  
!   if (GET_CODE (pat) == SET)
!     hash_scan_set (pat, insn, set_p);
    else if (GET_CODE (pat) == PARALLEL)
      for (i = 0; i < XVECLEN (pat, 0); i++)
*************** hash_scan_insn (insn, set_p, in_libcall_
*** 2008,2015 ****
  
  	if (GET_CODE (x) == SET)
! 	  {
! 	    if (GET_CODE (SET_SRC (x)) == CALL)
! 	      hash_scan_call (SET_SRC (x), insn);
! 	  }
  	else if (GET_CODE (x) == CLOBBER)
  	  hash_scan_clobber (x, insn);
--- 2018,2022 ----
  
  	if (GET_CODE (x) == SET)
! 	  hash_scan_set (x, insn, set_p);
  	else if (GET_CODE (x) == CLOBBER)
  	  hash_scan_clobber (x, insn);
*************** compute_kill_rd ()
*** 2612,2616 ****
  {
    int bb, cuid;
!   int regno, i;
  
    /* For each block
--- 2619,2624 ----
  {
    int bb, cuid;
!   unsigned int regno;
!   int i;
  
    /* For each block
*************** try_replace_reg (from, to, insn)
*** 3604,3664 ****
       rtx from, to, insn;
  {
!   rtx note;
    rtx src;
!   int success;
!   rtx set;
! 
!   note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
! 
!   if (!note)
!     note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
  
!   /* If this fails we could try to simplify the result of the
!      replacement and attempt to recognize the simplified insn.
! 
!      But we need a general simplify_rtx that doesn't have pass
!      specific state variables.  I'm not aware of one at the moment.  */
! 
!   success = validate_replace_src (from, to, insn);
!   set = single_set (insn);
! 
!   /* We've failed to do replacement. Try to add REG_EQUAL note to not loose
!      information.  */
!   if (!success && !note)
!     {
!       if (!set)
! 	return 0;
! 
!       note = REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL,
! 						   copy_rtx (SET_SRC (set)),
! 						   REG_NOTES (insn));
!     }
! 
!   /* Always do the replacement in REQ_EQUAL and REG_EQUIV notes.  Also
!      try to simplify them.  */
!   if (note)
!     {
!       rtx simplified;
! 
!       if (!validate_replace_rtx_subexp (from, to, insn, &XEXP (note, 0)))
! 	abort();
! 
!       src = XEXP (note, 0);
! 
!       /* Try to simplify resulting note. */
!       simplified = simplify_rtx (src);
!       if (simplified)
! 	{
! 	  src = simplified;
! 	  XEXP (note, 0) = src;
! 	}
  
-       /* REG_EQUAL may get simplified into register.
-          We don't allow that. Remove that note. This code ought
-          not to hapen, because previous code ought to syntetize
-          reg-reg move, but be on the safe side.  */
-       else if (REG_P (src))
- 	remove_note (insn, note);
-     }
    return success;
  }
--- 3612,3662 ----
       rtx from, to, insn;
  {
!   rtx note = find_reg_equal_equiv_note (insn);
    rtx src;
!   int success = 0;
!   rtx set = single_set (insn);
  
!   /* If this is a single set, try to simplify the source of the set given
!      our substitution.  We could perhaps try this for multiple SETs, but
!      it probably won't buy us anything.  */
!   if (set != 0)
!     {
!       src = simplify_replace_rtx (SET_SRC (set), from, to);
! 
!       /* Try this two ways: first just replace SET_SRC.  If that doesn't
! 	 work and this is a PARALLEL, try to replace the whole pattern
! 	 with a new SET.  */
!       if (validate_change (insn, &SET_SRC (set), src, 0))
! 	success = 1;
!       else if (GET_CODE (PATTERN (insn)) == PARALLEL
! 	       && validate_change (insn, &PATTERN (insn),
! 				   gen_rtx_SET (VOIDmode, SET_DEST (set),
! 						src),
! 				   0))
! 	success = 1;
!     }
! 
!   /* Otherwise, try to do a global replacement within the insn.  */
!   if (!success)
!     success = validate_replace_src (from, to, insn);
! 
!   /* We've failed to do replacement, have a single SET, and don't already
!      have a note, two to add a REG_EQUAL note to not lose information.  */
!   if (!success && note == 0 && set != 0)
!     note= REG_NOTES (insn)
!       = gen_rtx_EXPR_LIST (REG_EQUAL, src, REG_NOTES (insn));
! 
!   /* If there is already a NOTE, update the expression in it with our
!      replacement.  */
!   else if (note != 0)
!     XEXP (note, 0) = simplify_replace_rtx (XEXP (note, 0), from, to);
! 
!   /* REG_EQUAL may get simplified into register.
!      We don't allow that. Remove that note. This code ought
!      not to hapen, because previous code ought to syntetize
!      reg-reg move, but be on the safe side.  */
!   if (note && REG_P (XEXP (note, 0)))
!     remove_note (insn, note);
  
    return success;
  }
*************** find_avail_set (regno, insn)
*** 3735,3814 ****
  
  /* 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);
! 
!       run_jump_opt_after_gcse = 1;
  
!       const_prop_count++;
!       if (gcse_file != NULL)
! 	{
! 	  fprintf (gcse_file,
! 		   "CONST-PROP: Replacing reg %d in insn %d with constant ",
! 		   REGNO (reg_used->reg_rtx), INSN_UID (insn));
! 	  print_rtl (gcse_file, src);
! 	  fprintf (gcse_file, "\n");
! 	}
  
!       return 1;
      }
!   return 0;
  }
  
--- 3733,3787 ----
  
  /* Subroutine of cprop_insn that tries to propagate constants into
!    JUMP_INSNS.  INSN must be a conditional jump.  FROM is what we will try to
!    replace, SRC is the constant we will try to substitute for it.  Returns
!    nonzero if a change was made.  We know INSN has just a SET.  */
  
  static int
! cprop_jump (insn, from, src)
!      rtx insn;
!      rtx from;
       rtx src;
  {
!   rtx set = PATTERN (insn);
!   rtx new = simplify_replace_rtx (SET_SRC (set), from, src);
  
    /* If no simplification can be made, then try the next
       register.  */
!   if (rtx_equal_p (new, SET_SRC (set)))
      return 0;
   
!   /* If this is now a no-op leave it that way, but update LABEL_NUSED if
!      necessary.  */
!   if (new == pc_rtx)
!     {
!       SET_SRC (set) = new;
  
!       if (JUMP_LABEL (insn) != 0)
  	--LABEL_NUSES (JUMP_LABEL (insn));
!     }
  
!   /* Otherwise, this must be a valid instruction.  */
!   else if (! validate_change (insn, &SET_SRC (set), new, 0))
!     return 0;
  
!   /* 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;
! 
!   const_prop_count++;
!   if (gcse_file != NULL)
!     {
!       fprintf (gcse_file,
! 	       "CONST-PROP: Replacing reg %d in insn %d with constant ",
! 	       REGNO (from), INSN_UID (insn));
!       print_rtl (gcse_file, src);
!       fprintf (gcse_file, "\n");
      }
! 
!   return 1;
  }
  
*************** cprop_cc0_jump (insn, reg_used, src)
*** 3827,3838 ****
       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;
  
--- 3800,3810 ----
       rtx src;
  {
+   /* First substitute in the SET_SRC of INSN, then substitute that for
+      CC0 in JUMP.  */
    rtx jump = NEXT_INSN (insn);
!   rtx new_src = simplify_replace_rtx (SET_SRC (PATTERN (insn)),
! 				      reg_used->reg_rtx, src);
  
!   if (! cprop_jump (jump, cc0_rtx, new_src))
      return 0;
  
*************** cprop_insn (insn, alter_jumps)
*** 3859,3865 ****
    /* Only propagate into SETs.  Note that a conditional jump is a
       SET with pc_rtx as the destination.  */
!   if ((GET_CODE (insn) != INSN
!        && GET_CODE (insn) != JUMP_INSN)
!       || GET_CODE (PATTERN (insn)) != SET)
      return 0;
  
--- 3832,3836 ----
    /* Only propagate into SETs.  Note that a conditional jump is a
       SET with pc_rtx as the destination.  */
!   if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
      return 0;
  
*************** cprop_insn (insn, alter_jumps)
*** 3867,3873 ****
    find_used_regs (PATTERN (insn));
    
!   note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
!   if (!note)
!     note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
  
    /* We may win even when propagating constants into notes. */
--- 3838,3842 ----
    find_used_regs (PATTERN (insn));
    
!   note = find_reg_equal_equiv_note (insn);
  
    /* We may win even when propagating constants into notes. */
*************** cprop_insn (insn, alter_jumps)
*** 3939,3943 ****
  		   && condjump_p (insn)
  		   && ! simplejump_p (insn))
! 	    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
--- 3908,3913 ----
  		   && condjump_p (insn)
  		   && ! simplejump_p (insn))
! 	    changed |= cprop_jump (insn, reg_used->reg_rtx, src);
! 
  #ifdef HAVE_cc0
  	  /* Similar code for machines that use a pair of CC0 setter and
*************** cprop_insn (insn, alter_jumps)
*** 3948,3958 ****
  		   && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN
  		   && condjump_p (NEXT_INSN (insn))
! 		   && ! simplejump_p (NEXT_INSN (insn)))
!             {
! 	      if (cprop_cc0_jump (insn, reg_used, src))
! 		{
! 		  changed = 1;
! 		  break;
! 		}
  	    }
  #endif
--- 3918,3926 ----
  		   && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN
  		   && condjump_p (NEXT_INSN (insn))
! 		   && ! simplejump_p (NEXT_INSN (insn))
! 		   && cprop_cc0_jump (insn, reg_used, src))
! 	    {
! 	      changed = 1;
! 	      break;
  	    }
  #endif
*************** cprop (alter_jumps)
*** 4007,4021 ****
  	   insn != NULL && insn != NEXT_INSN (BLOCK_END (bb));
  	   insn = NEXT_INSN (insn))
! 	{
! 	  if (INSN_P (insn))
! 	    {
! 	      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.  Don't
! 	         call mark_oprs_set if we turned the insn into a NOTE.  */
! 	      if (GET_CODE (insn) != NOTE)
! 		mark_oprs_set (insn);
! 	    }
  	}
      }
--- 3975,3987 ----
  	   insn != NULL && insn != NEXT_INSN (BLOCK_END (bb));
  	   insn = NEXT_INSN (insn))
! 	if (INSN_P (insn))
! 	  {
! 	    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.  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]