[tree-ssa] Elliminate addressof

Jan Hubicka jh@suse.cz
Mon Feb 16 14:11:00 GMT 2004


Hi,
this is patch to remove addressof hack from the copmiler.  It produce code size
regression on Gerald's testcase so I've been holding it.  The problem are
constructs of scheme *(const char *)&char_variable produced by C++ frontend and
not elliminable on trees.  Richard and Andrew are working on the C++ frontend
fix, so i am posting the patch.

It removes a lot of hair from the backend, but I didn't get rit of ADDRESSOF
RTL construct itself.  Once it will be good timming to do so, I will get
rid of it together with CALL_PLACEHOLDER and other obsoletted constructs.

Zdenek's tester reports compilation time reduction from 3m2s to 2m58s on enable checking compiler, but it is in the noise level.
Bootstrapped/regtested i686-pc-gnu-linux. OK?

Honza

2004-02-16  Jan Hubicka  <jh@suse.cz>
	* function.c (put_addressof_into_stack, purge_addressof_1,
	purege_single_hard_subreg_set, is_addressof, insns_for_mem_hash,
	insns_for_mem_comp, postponed_insns): Remove.
	(put_var_into_stack): Really do it.
	(gen_mem_addressof): Remove.
	(put_addressof_into_stack): Remove.
	(purge_bitfield_addressof_replacements): Remove.
	(purge_addressof_replacements): Remove.
	(insns_for_mem_walk_info): Remove.
	(purge_addressof): Remove.
	* rtl.h (gen_mem_addressof, purge_addresof): Remove.
	* toplev.c (rest_of_handle_addressof): Remove.
	(dump_file_index): Remove addressof pass.
	(dump_file): Likewise.
	(rest_of_compilation): Do not call rest_of_handle_addressof
	(flush_addressof): Remove.

Index: function.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/function.c,v
retrieving revision 1.374.2.42
diff -c -3 -p -r1.374.2.42 function.c
*** function.c	13 Feb 2004 13:11:27 -0000	1.374.2.42
--- function.c	15 Feb 2004 20:21:54 -0000
*************** static int contains (rtx, varray_type);
*** 274,290 ****
  #ifdef HAVE_return
  static void emit_return_into_block (basic_block, rtx);
  #endif
- static void put_addressof_into_stack (rtx, htab_t);
- static bool purge_addressof_1 (rtx *, rtx, int, int, int, htab_t);
- static void purge_single_hard_subreg_set (rtx);
  #if defined(HAVE_epilogue) && defined(INCOMING_RETURN_ADDR_RTX)
  static rtx keep_stack_depressed (rtx);
  #endif
- static int is_addressof (rtx *, void *);
- static hashval_t insns_for_mem_hash (const void *);
- static int insns_for_mem_comp (const void *, const void *);
- static int insns_for_mem_walk (rtx *, void *);
- static void compute_insns_for_mem (rtx, rtx, htab_t);
  static void prepare_function_start (tree);
  static void do_clobber_return_reg (rtx, void *);
  static void do_use_return_reg (rtx, void *);
--- 274,282 ----
*************** static void set_insn_locators (rtx, int)
*** 295,303 ****
  /* Pointer to chain of `struct function' for containing functions.  */
  struct function *outer_function_chain;
  
- /* List of insns that were postponed by purge_addressof_1.  */
- static rtx postponed_insns;
- 
  /* Given a function decl for a containing function,
     return the `struct function' for it.  */
  
--- 287,292 ----
*************** put_var_into_stack (tree decl, int resca
*** 1288,1294 ****
    enum machine_mode promoted_mode, decl_mode;
    struct function *function = 0;
    tree context;
-   int can_use_addressof;
    int volatilep = TREE_CODE (decl) != SAVE_EXPR && TREE_THIS_VOLATILE (decl);
    int usedp = (TREE_USED (decl)
  	       || (TREE_CODE (decl) != SAVE_EXPR && DECL_INITIAL (decl) != 0));
--- 1277,1282 ----
*************** put_var_into_stack (tree decl, int resca
*** 1334,1368 ****
        decl_mode = promoted_mode = GET_MODE (reg);
      }
  
-   /* If this variable lives in the current function and we don't need to put it
-      in the stack for the sake of setjmp or the non-locality, try to keep it in
-      a register until we know we actually need the address.  */
-   can_use_addressof
-     = (function == 0
-        && ! (TREE_CODE (decl) != SAVE_EXPR && DECL_NONLOCAL (decl))
-        && optimize > 0
-        /* FIXME make it work for promoted modes too */
-        && decl_mode == promoted_mode
- #ifdef NON_SAVING_SETJMP
-        && ! (NON_SAVING_SETJMP && current_function_calls_setjmp)
- #endif
-        );
- 
-   /* If we can't use ADDRESSOF, make sure we see through one we already
-      generated.  */
-   if (! can_use_addressof && GET_CODE (reg) == MEM
-       && GET_CODE (XEXP (reg, 0)) == ADDRESSOF)
-     reg = XEXP (XEXP (reg, 0), 0);
- 
    /* Now we should have a value that resides in one or more pseudo regs.  */
  
    if (GET_CODE (reg) == REG)
      {
!       if (can_use_addressof)
! 	gen_mem_addressof (reg, decl, rescan);
!       else
! 	put_reg_into_stack (function, reg, TREE_TYPE (decl), promoted_mode,
! 			    decl_mode, volatilep, 0, usedp, 0);
      }
    else if (GET_CODE (reg) == CONCAT)
      {
--- 1322,1333 ----
        decl_mode = promoted_mode = GET_MODE (reg);
      }
  
    /* Now we should have a value that resides in one or more pseudo regs.  */
  
    if (GET_CODE (reg) == REG)
      {
!       put_reg_into_stack (function, reg, TREE_TYPE (decl), promoted_mode,
! 			  decl_mode, volatilep, 0, usedp, 0);
      }
    else if (GET_CODE (reg) == CONCAT)
      {
*************** static int cfa_offset;
*** 2812,3455 ****
  #ifndef ARG_POINTER_CFA_OFFSET
  #define ARG_POINTER_CFA_OFFSET(FNDECL) FIRST_PARM_OFFSET (FNDECL)
  #endif
- 
- /* Build up a (MEM (ADDRESSOF (REG))) rtx for a register REG that just
-    had its address taken.  DECL is the decl or SAVE_EXPR for the
-    object stored in the register, for later use if we do need to force
-    REG into the stack.  REG is overwritten by the MEM like in
-    put_reg_into_stack.  RESCAN is true if previously emitted
-    instructions must be rescanned and modified now that the REG has
-    been transformed.  */
- 
- rtx
- gen_mem_addressof (rtx reg, tree decl, int rescan)
- {
-   rtx r = gen_rtx_ADDRESSOF (Pmode, gen_reg_rtx (GET_MODE (reg)),
- 			     REGNO (reg), decl);
- 
-   /* Calculate this before we start messing with decl's RTL.  */
-   HOST_WIDE_INT set = decl ? get_alias_set (decl) : 0;
- 
-   /* If the original REG was a user-variable, then so is the REG whose
-      address is being taken.  Likewise for unchanging.  */
-   REG_USERVAR_P (XEXP (r, 0)) = REG_USERVAR_P (reg);
-   RTX_UNCHANGING_P (XEXP (r, 0)) = RTX_UNCHANGING_P (reg);
- 
-   PUT_CODE (reg, MEM);
-   MEM_ATTRS (reg) = 0;
-   XEXP (reg, 0) = r;
- 
-   if (decl)
-     {
-       tree type = TREE_TYPE (decl);
-       enum machine_mode decl_mode
- 	= (DECL_P (decl) ? DECL_MODE (decl) : TYPE_MODE (TREE_TYPE (decl)));
-       rtx decl_rtl = (TREE_CODE (decl) == SAVE_EXPR ? SAVE_EXPR_RTL (decl)
- 		      : DECL_RTL_IF_SET (decl));
- 
-       PUT_MODE (reg, decl_mode);
- 
-       /* Clear DECL_RTL momentarily so functions below will work
- 	 properly, then set it again.  */
-       if (DECL_P (decl) && decl_rtl == reg)
- 	SET_DECL_RTL (decl, 0);
- 
-       set_mem_attributes (reg, decl, 1);
-       set_mem_alias_set (reg, set);
- 
-       if (DECL_P (decl) && decl_rtl == reg)
- 	SET_DECL_RTL (decl, reg);
- 
-       if (rescan
- 	  && (TREE_USED (decl) || (DECL_P (decl) && DECL_INITIAL (decl) != 0)))
- 	fixup_var_refs (reg, GET_MODE (reg), TREE_UNSIGNED (type), reg, 0);
-     }
-   else if (rescan)
-     {
-       /* This can only happen during reload.  Clear the same flag bits as
- 	 reload.  */
-       MEM_VOLATILE_P (reg) = 0;
-       RTX_UNCHANGING_P (reg) = 0;
-       MEM_IN_STRUCT_P (reg) = 0;
-       MEM_SCALAR_P (reg) = 0;
-       MEM_ATTRS (reg) = 0;
- 
-       fixup_var_refs (reg, GET_MODE (reg), 0, reg, 0);
-     }
- 
-   return reg;
- }
- 
- /* If DECL has an RTL that is an ADDRESSOF rtx, put it into the stack.  */
- 
- void
- flush_addressof (tree decl)
- {
-   if ((TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == VAR_DECL)
-       && DECL_RTL (decl) != 0
-       && GET_CODE (DECL_RTL (decl)) == MEM
-       && GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF
-       && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == REG)
-     put_addressof_into_stack (XEXP (DECL_RTL (decl), 0), 0);
- }
- 
- /* Force the register pointed to by R, an ADDRESSOF rtx, into the stack.  */
- 
- static void
- put_addressof_into_stack (rtx r, htab_t ht)
- {
-   tree decl, type;
-   int volatile_p, used_p;
- 
-   rtx reg = XEXP (r, 0);
- 
-   if (GET_CODE (reg) != REG)
-     abort ();
- 
-   decl = ADDRESSOF_DECL (r);
-   if (decl)
-     {
-       type = TREE_TYPE (decl);
-       volatile_p = (TREE_CODE (decl) != SAVE_EXPR
- 		    && TREE_THIS_VOLATILE (decl));
-       used_p = (TREE_USED (decl)
- 		|| (DECL_P (decl) && DECL_INITIAL (decl) != 0));
-     }
-   else
-     {
-       type = NULL_TREE;
-       volatile_p = 0;
-       used_p = 1;
-     }
- 
-   put_reg_into_stack (0, reg, type, GET_MODE (reg), GET_MODE (reg),
- 		      volatile_p, ADDRESSOF_REGNO (r), used_p, ht);
- }
- 
- /* List of replacements made below in purge_addressof_1 when creating
-    bitfield insertions.  */
- static rtx purge_bitfield_addressof_replacements;
- 
- /* List of replacements made below in purge_addressof_1 for patterns
-    (MEM (ADDRESSOF (REG ...))).  The key of the list entry is the
-    corresponding (ADDRESSOF (REG ...)) and value is a substitution for
-    the all pattern.  List PURGE_BITFIELD_ADDRESSOF_REPLACEMENTS is not
-    enough in complex cases, e.g. when some field values can be
-    extracted by usage MEM with narrower mode.  */
- static rtx purge_addressof_replacements;
- 
- /* Helper function for purge_addressof.  See if the rtx expression at *LOC
-    in INSN needs to be changed.  If FORCE, always put any ADDRESSOFs into
-    the stack.  If the function returns FALSE then the replacement could not
-    be made.  If MAY_POSTPONE is true and we would not put the addressof
-    to stack, postpone processing of the insn.  */
- 
- static bool
- purge_addressof_1 (rtx *loc, rtx insn, int force, int store, int may_postpone,
- 		   htab_t ht)
- {
-   rtx x;
-   RTX_CODE code;
-   int i, j;
-   const char *fmt;
-   bool result = true;
-   bool libcall = false;
- 
-   /* Re-start here to avoid recursion in common cases.  */
-  restart:
- 
-   x = *loc;
-   if (x == 0)
-     return true;
- 
-   /* Is this a libcall?  */
-   if (!insn)
-     libcall = REG_NOTE_KIND (*loc) == REG_RETVAL;
- 
-   code = GET_CODE (x);
- 
-   /* If we don't return in any of the cases below, we will recurse inside
-      the RTX, which will normally result in any ADDRESSOF being forced into
-      memory.  */
-   if (code == SET)
-     {
-       result = purge_addressof_1 (&SET_DEST (x), insn, force, 1,
- 				  may_postpone, ht);
-       result &= purge_addressof_1 (&SET_SRC (x), insn, force, 0,
- 				   may_postpone, ht);
-       return result;
-     }
-   else if (code == ADDRESSOF)
-     {
-       rtx sub, insns;
- 
-       if (GET_CODE (XEXP (x, 0)) != MEM)
- 	put_addressof_into_stack (x, ht);
- 
-       /* We must create a copy of the rtx because it was created by
- 	 overwriting a REG rtx which is always shared.  */
-       sub = copy_rtx (XEXP (XEXP (x, 0), 0));
-       if (validate_change (insn, loc, sub, 0)
- 	  || validate_replace_rtx (x, sub, insn))
- 	return true;
- 
-       start_sequence ();
- 
-       /* If SUB is a hard or virtual register, try it as a pseudo-register.
- 	 Otherwise, perhaps SUB is an expression, so generate code to compute
- 	 it.  */
-       if (GET_CODE (sub) == REG && REGNO (sub) <= LAST_VIRTUAL_REGISTER)
- 	sub = copy_to_reg (sub);
-       else
- 	sub = force_operand (sub, NULL_RTX);
- 
-       if (! validate_change (insn, loc, sub, 0)
- 	  && ! validate_replace_rtx (x, sub, insn))
- 	abort ();
- 
-       insns = get_insns ();
-       end_sequence ();
-       emit_insn_before (insns, insn);
-       return true;
-     }
- 
-   else if (code == MEM && GET_CODE (XEXP (x, 0)) == ADDRESSOF && ! force)
-     {
-       rtx sub = XEXP (XEXP (x, 0), 0);
- 
-       if (GET_CODE (sub) == MEM)
- 	sub = adjust_address_nv (sub, GET_MODE (x), 0);
-       else if (GET_CODE (sub) == REG
- 	       && (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode))
- 	;
-       else if (GET_CODE (sub) == REG && GET_MODE (x) != GET_MODE (sub))
- 	{
- 	  int size_x, size_sub;
- 
- 	  if (may_postpone)
- 	    {
- 	      /* Postpone for now, so that we do not emit bitfield arithmetics
- 		 unless there is some benefit from it.  */
- 	      if (!postponed_insns || XEXP (postponed_insns, 0) != insn)
- 		postponed_insns = alloc_INSN_LIST (insn, postponed_insns);
- 	      return true;
- 	    }
- 
- 	  if (!insn)
- 	    {
- 	      /* When processing REG_NOTES look at the list of
- 		 replacements done on the insn to find the register that X
- 		 was replaced by.  */
- 	      rtx tem;
- 
- 	      for (tem = purge_bitfield_addressof_replacements;
- 		   tem != NULL_RTX;
- 		   tem = XEXP (XEXP (tem, 1), 1))
- 		if (rtx_equal_p (x, XEXP (tem, 0)))
- 		  {
- 		    *loc = XEXP (XEXP (tem, 1), 0);
- 		    return true;
- 		  }
- 
- 	      /* See comment for purge_addressof_replacements.  */
- 	      for (tem = purge_addressof_replacements;
- 		   tem != NULL_RTX;
- 		   tem = XEXP (XEXP (tem, 1), 1))
- 		if (rtx_equal_p (XEXP (x, 0), XEXP (tem, 0)))
- 		  {
- 		    rtx z = XEXP (XEXP (tem, 1), 0);
- 
- 		    if (GET_MODE (x) == GET_MODE (z)
- 			|| (GET_CODE (XEXP (XEXP (tem, 1), 0)) != REG
- 			    && GET_CODE (XEXP (XEXP (tem, 1), 0)) != SUBREG))
- 		      abort ();
- 
- 		    /* It can happen that the note may speak of things
- 		       in a wider (or just different) mode than the
- 		       code did.  This is especially true of
- 		       REG_RETVAL.  */
- 
- 		    if (GET_CODE (z) == SUBREG && SUBREG_BYTE (z) == 0)
- 		      z = SUBREG_REG (z);
- 
- 		    if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD
- 			&& (GET_MODE_SIZE (GET_MODE (x))
- 			    > GET_MODE_SIZE (GET_MODE (z))))
- 		      {
- 			/* This can occur as a result in invalid
- 			   pointer casts, e.g. float f; ...
- 			   *(long long int *)&f.
- 			   ??? We could emit a warning here, but
- 			   without a line number that wouldn't be
- 			   very helpful.  */
- 			z = gen_rtx_SUBREG (GET_MODE (x), z, 0);
- 		      }
- 		    else
- 		      z = gen_lowpart (GET_MODE (x), z);
- 
- 		    *loc = z;
- 		    return true;
- 		  }
- 
- 	      /* When we are processing the REG_NOTES of the last instruction
- 		 of a libcall, there will be typically no replacements
- 		 for that insn; the replacements happened before, piecemeal
- 		 fashion.  OTOH we are not interested in the details of
- 		 this for the REG_EQUAL note, we want to know the big picture,
- 		 which can be succinctly described with a simple SUBREG.
- 		 Note that removing the REG_EQUAL note is not an option
- 		 on the last insn of a libcall, so we must do a replacement.  */
- 
- 	      /* In compile/990107-1.c:7 compiled at -O1 -m1 for sh-elf,
- 		 we got
- 		 (mem:DI (addressof:SI (reg/v:DF 160) 159 0x401c8510)
- 		 [0 S8 A32]), which can be expressed with a simple
- 		 same-size subreg  */
- 	      if ((GET_MODE_SIZE (GET_MODE (x))
- 		   <= GET_MODE_SIZE (GET_MODE (sub)))
- 		  /* Again, invalid pointer casts (as in
- 		     compile/990203-1.c) can require paradoxical
- 		     subregs.  */
- 		  || (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD
- 		      && (GET_MODE_SIZE (GET_MODE (x))
- 			  > GET_MODE_SIZE (GET_MODE (sub)))
- 		      && libcall))
- 		{
- 		  *loc = gen_rtx_SUBREG (GET_MODE (x), sub, 0);
- 		  return true;
- 		}
- 	      /* ??? Are there other cases we should handle?  */
- 
- 	      /* Sometimes we may not be able to find the replacement.  For
- 		 example when the original insn was a MEM in a wider mode,
- 		 and the note is part of a sign extension of a narrowed
- 		 version of that MEM.  Gcc testcase compile/990829-1.c can
- 		 generate an example of this situation.  Rather than complain
- 		 we return false, which will prompt our caller to remove the
- 		 offending note.  */
- 	      return false;
- 	    }
- 
- 	  size_x = GET_MODE_BITSIZE (GET_MODE (x));
- 	  size_sub = GET_MODE_BITSIZE (GET_MODE (sub));
- 
- 	  /* Do not frob unchanging MEMs.  If a later reference forces the
- 	     pseudo to the stack, we can wind up with multiple writes to
- 	     an unchanging memory, which is invalid.  */
- 	  if (RTX_UNCHANGING_P (x) && size_x != size_sub)
- 	    ;
- 
- 	  /* Don't even consider working with paradoxical subregs,
- 	     or the moral equivalent seen here.  */
- 	  else if (size_x <= size_sub
- 	           && int_mode_for_mode (GET_MODE (sub)) != BLKmode)
- 	    {
- 	      /* Do a bitfield insertion to mirror what would happen
- 		 in memory.  */
- 
- 	      rtx val, seq;
- 
- 	      if (store)
- 		{
- 		  rtx p = PREV_INSN (insn);
- 
- 		  start_sequence ();
- 		  val = gen_reg_rtx (GET_MODE (x));
- 		  if (! validate_change (insn, loc, val, 0))
- 		    {
- 		      /* Discard the current sequence and put the
- 			 ADDRESSOF on stack.  */
- 		      end_sequence ();
- 		      goto give_up;
- 		    }
- 		  seq = get_insns ();
- 		  end_sequence ();
- 		  emit_insn_before (seq, insn);
- 		  compute_insns_for_mem (p ? NEXT_INSN (p) : get_insns (),
- 					 insn, ht);
- 
- 		  start_sequence ();
- 		  store_bit_field (sub, size_x, 0, GET_MODE (x),
- 				   val, GET_MODE_SIZE (GET_MODE (sub)));
- 
- 		  /* Make sure to unshare any shared rtl that store_bit_field
- 		     might have created.  */
- 		  unshare_all_rtl_again (get_insns ());
- 
- 		  seq = get_insns ();
- 		  end_sequence ();
- 		  p = emit_insn_after (seq, insn);
- 		  if (NEXT_INSN (insn))
- 		    compute_insns_for_mem (NEXT_INSN (insn),
- 					   p ? NEXT_INSN (p) : NULL_RTX,
- 					   ht);
- 		}
- 	      else
- 		{
- 		  rtx p = PREV_INSN (insn);
- 
- 		  start_sequence ();
- 		  val = extract_bit_field (sub, size_x, 0, 1, NULL_RTX,
- 					   GET_MODE (x), GET_MODE (x),
- 					   GET_MODE_SIZE (GET_MODE (sub)));
- 
- 		  if (! validate_change (insn, loc, val, 0))
- 		    {
- 		      /* Discard the current sequence and put the
- 			 ADDRESSOF on stack.  */
- 		      end_sequence ();
- 		      goto give_up;
- 		    }
- 
- 		  seq = get_insns ();
- 		  end_sequence ();
- 		  emit_insn_before (seq, insn);
- 		  compute_insns_for_mem (p ? NEXT_INSN (p) : get_insns (),
- 					 insn, ht);
- 		}
- 
- 	      /* Remember the replacement so that the same one can be done
- 		 on the REG_NOTES.  */
- 	      purge_bitfield_addressof_replacements
- 		= gen_rtx_EXPR_LIST (VOIDmode, x,
- 				     gen_rtx_EXPR_LIST
- 				     (VOIDmode, val,
- 				      purge_bitfield_addressof_replacements));
- 
- 	      /* We replaced with a reg -- all done.  */
- 	      return true;
- 	    }
- 	}
- 
-       else if (validate_change (insn, loc, sub, 0))
- 	{
- 	  /* Remember the replacement so that the same one can be done
- 	     on the REG_NOTES.  */
- 	  if (GET_CODE (sub) == REG || GET_CODE (sub) == SUBREG)
- 	    {
- 	      rtx tem;
- 
- 	      for (tem = purge_addressof_replacements;
- 		   tem != NULL_RTX;
- 		   tem = XEXP (XEXP (tem, 1), 1))
- 		if (rtx_equal_p (XEXP (x, 0), XEXP (tem, 0)))
- 		  {
- 		    XEXP (XEXP (tem, 1), 0) = sub;
- 		    return true;
- 		  }
- 	      purge_addressof_replacements
- 		= gen_rtx_EXPR_LIST (VOIDmode, XEXP (x, 0),
- 				     gen_rtx_EXPR_LIST (VOIDmode, sub,
- 							purge_addressof_replacements));
- 	      return true;
- 	    }
- 	  goto restart;
- 	}
-     }
- 
-  give_up:
-   /* Scan all subexpressions.  */
-   fmt = GET_RTX_FORMAT (code);
-   for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
-     {
-       if (*fmt == 'e')
- 	result &= purge_addressof_1 (&XEXP (x, i), insn, force, 0,
- 				     may_postpone, ht);
-       else if (*fmt == 'E')
- 	for (j = 0; j < XVECLEN (x, i); j++)
- 	  result &= purge_addressof_1 (&XVECEXP (x, i, j), insn, force, 0,
- 				       may_postpone, ht);
-     }
- 
-   return result;
- }
- 
- /* Return a hash value for K, a REG.  */
- 
- static hashval_t
- insns_for_mem_hash (const void *k)
- {
-   /* Use the address of the key for the hash value.  */
-   struct insns_for_mem_entry *m = (struct insns_for_mem_entry *) k;
-   return htab_hash_pointer (m->key);
- }
- 
- /* Return nonzero if K1 and K2 (two REGs) are the same.  */
- 
- static int
- insns_for_mem_comp (const void *k1, const void *k2)
- {
-   struct insns_for_mem_entry *m1 = (struct insns_for_mem_entry *) k1;
-   struct insns_for_mem_entry *m2 = (struct insns_for_mem_entry *) k2;
-   return m1->key == m2->key;
- }
- 
- struct insns_for_mem_walk_info
- {
-   /* The hash table that we are using to record which INSNs use which
-      MEMs.  */
-   htab_t ht;
- 
-   /* The INSN we are currently processing.  */
-   rtx insn;
- 
-   /* Zero if we are walking to find ADDRESSOFs, one if we are walking
-      to find the insns that use the REGs in the ADDRESSOFs.  */
-   int pass;
- };
- 
- /* Called from compute_insns_for_mem via for_each_rtx.  If R is a REG
-    that might be used in an ADDRESSOF expression, record this INSN in
-    the hash table given by DATA (which is really a pointer to an
-    insns_for_mem_walk_info structure).  */
- 
- static int
- insns_for_mem_walk (rtx *r, void *data)
- {
-   struct insns_for_mem_walk_info *ifmwi
-     = (struct insns_for_mem_walk_info *) data;
-   struct insns_for_mem_entry tmp;
-   tmp.insns = NULL_RTX;
- 
-   if (ifmwi->pass == 0 && *r && GET_CODE (*r) == ADDRESSOF
-       && GET_CODE (XEXP (*r, 0)) == REG)
-     {
-       void **e;
-       tmp.key = XEXP (*r, 0);
-       e = htab_find_slot (ifmwi->ht, &tmp, INSERT);
-       if (*e == NULL)
- 	{
- 	  *e = ggc_alloc (sizeof (tmp));
- 	  memcpy (*e, &tmp, sizeof (tmp));
- 	}
-     }
-   else if (ifmwi->pass == 1 && *r && GET_CODE (*r) == REG)
-     {
-       struct insns_for_mem_entry *ifme;
-       tmp.key = *r;
-       ifme = htab_find (ifmwi->ht, &tmp);
- 
-       /* If we have not already recorded this INSN, do so now.  Since
- 	 we process the INSNs in order, we know that if we have
- 	 recorded it it must be at the front of the list.  */
-       if (ifme && (!ifme->insns || XEXP (ifme->insns, 0) != ifmwi->insn))
- 	ifme->insns = gen_rtx_EXPR_LIST (VOIDmode, ifmwi->insn,
- 					 ifme->insns);
-     }
- 
-   return 0;
- }
- 
- /* Walk the INSNS, until we reach LAST_INSN, recording which INSNs use
-    which REGs in HT.  */
- 
- static void
- compute_insns_for_mem (rtx insns, rtx last_insn, htab_t ht)
- {
-   rtx insn;
-   struct insns_for_mem_walk_info ifmwi;
-   ifmwi.ht = ht;
- 
-   for (ifmwi.pass = 0; ifmwi.pass < 2; ++ifmwi.pass)
-     for (insn = insns; insn != last_insn; insn = NEXT_INSN (insn))
-       if (INSN_P (insn))
- 	{
- 	  ifmwi.insn = insn;
- 	  for_each_rtx (&insn, insns_for_mem_walk, &ifmwi);
- 	}
- }
- 
- /* Helper function for purge_addressof called through for_each_rtx.
-    Returns true iff the rtl is an ADDRESSOF.  */
- 
- static int
- is_addressof (rtx *rtl, void *data ATTRIBUTE_UNUSED)
- {
-   return GET_CODE (*rtl) == ADDRESSOF;
- }
- 
- /* Eliminate all occurrences of ADDRESSOF from INSNS.  Elide any remaining
-    (MEM (ADDRESSOF)) patterns, and force any needed registers into the
-    stack.  */
- 
- void
- purge_addressof (rtx insns)
- {
-   rtx insn, tmp;
-   htab_t ht;
- 
-   /* When we actually purge ADDRESSOFs, we turn REGs into MEMs.  That
-      requires a fixup pass over the instruction stream to correct
-      INSNs that depended on the REG being a REG, and not a MEM.  But,
-      these fixup passes are slow.  Furthermore, most MEMs are not
-      mentioned in very many instructions.  So, we speed up the process
-      by pre-calculating which REGs occur in which INSNs; that allows
-      us to perform the fixup passes much more quickly.  */
-   ht = htab_create_ggc (1000, insns_for_mem_hash, insns_for_mem_comp, NULL);
-   compute_insns_for_mem (insns, NULL_RTX, ht);
- 
-   postponed_insns = NULL;
- 
-   for (insn = insns; insn; insn = NEXT_INSN (insn))
-     if (INSN_P (insn))
-       {
- 	if (! purge_addressof_1 (&PATTERN (insn), insn,
- 				 asm_noperands (PATTERN (insn)) > 0, 0, 1, ht))
- 	  /* If we could not replace the ADDRESSOFs in the insn,
- 	     something is wrong.  */
- 	  abort ();
- 
- 	if (! purge_addressof_1 (&REG_NOTES (insn), NULL_RTX, 0, 0, 0, ht))
- 	  {
- 	    /* If we could not replace the ADDRESSOFs in the insn's notes,
- 	       we can just remove the offending notes instead.  */
- 	    rtx note;
- 
- 	    for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
- 	      {
- 		/* If we find a REG_RETVAL note then the insn is a libcall.
- 		   Such insns must have REG_EQUAL notes as well, in order
- 		   for later passes of the compiler to work.  So it is not
- 		   safe to delete the notes here, and instead we abort.  */
- 		if (REG_NOTE_KIND (note) == REG_RETVAL)
- 		  abort ();
- 		if (for_each_rtx (&note, is_addressof, NULL))
- 		  remove_note (insn, note);
- 	      }
- 	  }
-       }
- 
-   /* Process the postponed insns.  */
-   while (postponed_insns)
-     {
-       insn = XEXP (postponed_insns, 0);
-       tmp = postponed_insns;
-       postponed_insns = XEXP (postponed_insns, 1);
-       free_INSN_LIST_node (tmp);
- 
-       if (! purge_addressof_1 (&PATTERN (insn), insn,
- 			       asm_noperands (PATTERN (insn)) > 0, 0, 0, ht))
- 	abort ();
-     }
- 
-   /* Clean up.  */
-   purge_bitfield_addressof_replacements = 0;
-   purge_addressof_replacements = 0;
- 
-   /* REGs are shared.  purge_addressof will destructively replace a REG
-      with a MEM, which creates shared MEMs.
- 
-      Unfortunately, the children of put_reg_into_stack assume that MEMs
-      referring to the same stack slot are shared (fixup_var_refs and
-      the associated hash table code).
- 
-      So, we have to do another unsharing pass after we have flushed any
-      REGs that had their address taken into the stack.
- 
-      It may be worth tracking whether or not we converted any REGs into
-      MEMs to avoid this overhead when it is not needed.  */
-   unshare_all_rtl_again (get_insns ());
- }
  
  /* Convert a SET of a hard subreg to a set of the appropriate hard
     register.  A subroutine of purge_hard_subreg_sets.  */
--- 2777,2782 ----
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.362.2.34
diff -c -3 -p -r1.362.2.34 rtl.h
*** rtl.h	13 Feb 2004 13:11:47 -0000	1.362.2.34
--- rtl.h	15 Feb 2004 20:21:54 -0000
*************** extern rtx simplify_replace_rtx (rtx, rt
*** 1659,1667 ****
  extern rtx simplify_rtx (rtx);
  extern rtx avoid_constant_pool_reference (rtx);
  
- /* In function.c  */
- extern rtx gen_mem_addressof (rtx, tree, int);
- 
  /* In regclass.c  */
  extern enum machine_mode choose_hard_reg_mode (unsigned int, unsigned int,
  					       bool);
--- 1659,1664 ----
*************** extern int sibcall_epilogue_contains (rt
*** 2157,2163 ****
  extern void preserve_rtl_expr_result (rtx);
  extern void mark_temp_addr_taken (rtx);
  extern void update_temp_slot_address (rtx, rtx);
- extern void purge_addressof (rtx);
  extern void purge_hard_subreg_sets (rtx);
  
  /* In stmt.c */
--- 2154,2159 ----
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.654.2.97
diff -c -3 -p -r1.654.2.97 toplev.c
*** toplev.c	13 Feb 2004 13:11:52 -0000	1.654.2.97
--- toplev.c	15 Feb 2004 20:21:55 -0000
*************** static void rest_of_handle_loop_optimize
*** 138,144 ****
  static void rest_of_handle_loop2 (tree, rtx);
  static void rest_of_handle_jump_bypass (tree, rtx);
  static void rest_of_handle_null_pointer (tree, rtx);
- static void rest_of_handle_addressof (tree, rtx);
  static void rest_of_handle_cfg (tree, rtx);
  static void rest_of_handle_branch_prob (tree, rtx);
  static void rest_of_handle_value_profile_transformations (tree, rtx);
--- 138,143 ----
*************** enum dump_file_index
*** 262,268 ****
    DFI_jump,
    DFI_null,
    DFI_cse,
-   DFI_addressof,
    DFI_gcse,
    DFI_loop,
    DFI_bypass,
--- 261,266 ----
*************** static struct dump_file_info dump_file[D
*** 314,320 ****
    { "jump",	'j', 0, 0, 0 },
    { "null",	'u', 0, 0, 0 },
    { "cse",	's', 0, 0, 0 },
-   { "addressof", 'F', 0, 0, 0 },
    { "gcse",	'G', 1, 0, 0 },
    { "loop",	'L', 1, 0, 0 },
    { "bypass",   'G', 1, 0, 0 }, /* Yes, duplicate enable switch.  */
--- 312,317 ----
*************** rest_of_handle_cfg (tree decl, rtx insns
*** 2628,2647 ****
    close_dump_file (DFI_cfg, print_rtl_with_bb, insns);
  }
  
- /* Purge addressofs.  */
- static void
- rest_of_handle_addressof (tree decl, rtx insns)
- {
-   open_dump_file (DFI_addressof, decl);
- 
-   purge_addressof (insns);
-   if (optimize && purge_all_dead_edges (0))
-     delete_unreachable_blocks ();
-   reg_scan (insns, max_reg_num (), 1);
- 
-   close_dump_file (DFI_addressof, print_rtl, insns);
- }
- 
  /* Perform jump bypassing and control flow optimizations.  */
  static void
  rest_of_handle_jump_bypass (tree decl, rtx insns)
--- 2625,2630 ----
*************** rest_of_compilation (tree decl)
*** 3372,3379 ****
  
    if (optimize > 0)
      rest_of_handle_cse (decl, insns);
- 
-   rest_of_handle_addressof (decl, insns);
  
    ggc_collect ();
  
--- 3355,3360 ----
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.342.2.169
diff -c -3 -p -r1.342.2.169 tree.h
*** tree.h	13 Feb 2004 13:11:57 -0000	1.342.2.169
--- tree.h	15 Feb 2004 20:21:55 -0000
*************** extern void allocate_struct_function (tr
*** 3384,3390 ****
  extern void init_function_start (tree);
  extern void assign_parms (tree);
  extern void put_var_into_stack (tree, int);
- extern void flush_addressof (tree);
  extern void setjmp_vars_warning (tree);
  extern void setjmp_args_warning (void);
  extern void mark_all_temps_used (void);
--- 3384,3389 ----



More information about the Gcc-patches mailing list