PATCH for purge_addressof sluggishness

Mark Mitchell mark@codesourcery.com
Wed Mar 31 18:59:00 GMT 1999


>>>>> "Richard" == Richard Henderson <rth@cygnus.com> writes:

    Richard> Certainly you could do a three pass scheme -- look for
    Richard> addressof, look for pseudo uses, convert addressof.  That
    Richard> would probably minimize memory usage for only a little
    Richard> extra work.

This seemed worth doing, and wasn't hard.  So, I put in the attached
patch.

-- 
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

Mon Mar 22 10:53:59 1999  Mark Mitchell  <mark@codesourcery.com>

	* function.c: Include hash.h.
	(insns_for_mem_entry): New struct.
	(put_reg_into_stack): Take an optional hash-table mapping MEMs to
	the INSNs that use them.
	(fixup_var_refs): Likewise.
	(put_addressof_into_stack): Likewise.
	(purge_addressof_1): Likewise.  Keep the hash-table up to date if
	we add new instructions.
	(fixup_var_refs_insns): Use it to avoid searching the entire
	instruction chain.
	(insns_for_mem_newfunc): New function.
	(insns_for_mem_comp): Likewise.
	(insns_for_mem_walk): Likewise.
	(compute_insns_for_mem): Likewise.
	(pop_function_context_from): Pass NULL for the hash-table.
	(put_var_into_stack): Likewise.
	(gen_mem_addressof): Likewise.
	(flush_addressof): Likewise.
	(purge_addressof): Call compute_insns_for_mem to pre-compute the
	hash table.
	* Makefile.in (OBJS): Include hash.o.
	(function.o): Depend on hash.h.
	
1999-03-22  Mark Mitchell  <mark@codesourcery.com>

	* Makefile.in (OBJS): Don't mention hash.o.
	(OBJDEPS): Likewise.

Index: function.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/function.c,v
retrieving revision 1.80
diff -c -p -r1.80 function.c
*** function.c	1999/03/17 12:17:02	1.80
--- function.c	1999/03/23 15:45:11
*************** Boston, MA 02111-1307, USA.  */
*** 56,61 ****
--- 56,62 ----
  #include "basic-block.h"
  #include "obstack.h"
  #include "toplev.h"
+ #include "hash.h"
  
  #if !defined PREFERRED_STACK_BOUNDARY && defined STACK_BOUNDARY
  #define PREFERRED_STACK_BOUNDARY STACK_BOUNDARY
*************** struct fixup_replacement
*** 451,456 ****
--- 452,464 ----
    struct fixup_replacement *next;
  };
     
+ struct insns_for_mem_entry {
+   /* The KEY in HE will be a MEM.  */
+   struct hash_entry he;
+   /* These are the INSNS which reference the MEM.  */
+   rtx insns;
+ };
+ 
  /* Forward declarations.  */
  
  static rtx assign_outer_stack_local PROTO ((enum machine_mode, HOST_WIDE_INT,
*************** static rtx assign_stack_temp_for_type PR
*** 460,471 ****
  static struct temp_slot *find_temp_slot_from_address  PROTO((rtx));
  static void put_reg_into_stack	PROTO((struct function *, rtx, tree,
  				       enum machine_mode, enum machine_mode,
! 				       int, int, int));
! static void fixup_var_refs	PROTO((rtx, enum machine_mode, int));
  static struct fixup_replacement
    *find_fixup_replacement	PROTO((struct fixup_replacement **, rtx));
  static void fixup_var_refs_insns PROTO((rtx, enum machine_mode, int,
! 					rtx, int));
  static void fixup_var_refs_1	PROTO((rtx, enum machine_mode, rtx *, rtx,
  				       struct fixup_replacement **));
  static rtx fixup_memory_subreg	PROTO((rtx, rtx, int));
--- 468,481 ----
  static struct temp_slot *find_temp_slot_from_address  PROTO((rtx));
  static void put_reg_into_stack	PROTO((struct function *, rtx, tree,
  				       enum machine_mode, enum machine_mode,
! 				       int, int, int, 
! 				       struct hash_table *));
! static void fixup_var_refs	PROTO((rtx, enum machine_mode, int, 
! 				       struct hash_table *));
  static struct fixup_replacement
    *find_fixup_replacement	PROTO((struct fixup_replacement **, rtx));
  static void fixup_var_refs_insns PROTO((rtx, enum machine_mode, int,
! 					rtx, int, struct hash_table *));
  static void fixup_var_refs_1	PROTO((rtx, enum machine_mode, rtx *, rtx,
  				       struct fixup_replacement **));
  static rtx fixup_memory_subreg	PROTO((rtx, rtx, int));
*************** static int all_blocks		PROTO((tree, tree
*** 492,499 ****
  static int *record_insns	PROTO((rtx));
  static int contains		PROTO((rtx, int *));
  #endif /* HAVE_prologue || HAVE_epilogue */
! static void put_addressof_into_stack PROTO((rtx));
! static void purge_addressof_1	PROTO((rtx *, rtx, int, int));
  
  /* Pointer to chain of `struct function' for containing functions.  */
  struct function *outer_function_chain;
--- 502,518 ----
  static int *record_insns	PROTO((rtx));
  static int contains		PROTO((rtx, int *));
  #endif /* HAVE_prologue || HAVE_epilogue */
! static void put_addressof_into_stack PROTO((rtx, struct hash_table *));
! static void purge_addressof_1	PROTO((rtx *, rtx, int, int, 
! 				       struct hash_table *));
! static struct hash_entry *insns_for_mem_newfunc PROTO((struct hash_entry *,
! 						       struct hash_table *,
! 						       hash_table_key));
! static unsigned long insns_for_mem_hash PROTO ((hash_table_key));
! static boolean insns_for_mem_comp PROTO ((hash_table_key, hash_table_key));
! static int insns_for_mem_walk   PROTO ((rtx *, void *));
! static void compute_insns_for_mem PROTO ((rtx, rtx, struct hash_table *));
! 
  
  /* Pointer to chain of `struct function' for containing functions.  */
  struct function *outer_function_chain;
*************** pop_function_context_from (context)
*** 683,689 ****
    /* Finish doing put_var_into_stack for any of our variables
       which became addressable during the nested function.  */
    for (queue = p->fixup_var_refs_queue; queue; queue = queue->next)
!     fixup_var_refs (queue->modified, queue->promoted_mode, queue->unsignedp);
  
    free (p);
  
--- 702,709 ----
    /* Finish doing put_var_into_stack for any of our variables
       which became addressable during the nested function.  */
    for (queue = p->fixup_var_refs_queue; queue; queue = queue->next)
!     fixup_var_refs (queue->modified, queue->promoted_mode,
! 		    queue->unsignedp, 0);
  
    free (p);
  
*************** put_var_into_stack (decl)
*** 1569,1576 ****
  	put_reg_into_stack (function, reg, TREE_TYPE (decl),
  			    promoted_mode, decl_mode,
  			    TREE_SIDE_EFFECTS (decl), 0,
! 			    TREE_USED (decl)
! 			    || DECL_INITIAL (decl) != 0);
      }
    else if (GET_CODE (reg) == CONCAT)
      {
--- 1589,1596 ----
  	put_reg_into_stack (function, reg, TREE_TYPE (decl),
  			    promoted_mode, decl_mode,
  			    TREE_SIDE_EFFECTS (decl), 0,
! 			    TREE_USED (decl) || DECL_INITIAL (decl) != 0,
! 			    0);
      }
    else if (GET_CODE (reg) == CONCAT)
      {
*************** put_var_into_stack (decl)
*** 1582,1598 ****
        /* Since part 0 should have a lower address, do it second.  */
        put_reg_into_stack (function, XEXP (reg, 1), part_type, part_mode,
  			  part_mode, TREE_SIDE_EFFECTS (decl), 0,
! 			  TREE_USED (decl) || DECL_INITIAL (decl) != 0);
        put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,
  			  part_mode, TREE_SIDE_EFFECTS (decl), 0,
! 			  TREE_USED (decl) || DECL_INITIAL (decl) != 0);
  #else
        put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,
  			  part_mode, TREE_SIDE_EFFECTS (decl), 0,
! 			  TREE_USED (decl) || DECL_INITIAL (decl) != 0);
        put_reg_into_stack (function, XEXP (reg, 1), part_type, part_mode,
  			  part_mode, TREE_SIDE_EFFECTS (decl), 0,
! 			  TREE_USED (decl) || DECL_INITIAL (decl) != 0);
  #endif
  
        /* Change the CONCAT into a combined MEM for both parts.  */
--- 1602,1622 ----
        /* Since part 0 should have a lower address, do it second.  */
        put_reg_into_stack (function, XEXP (reg, 1), part_type, part_mode,
  			  part_mode, TREE_SIDE_EFFECTS (decl), 0,
! 			  TREE_USED (decl) || DECL_INITIAL (decl) != 0,
! 			  0);
        put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,
  			  part_mode, TREE_SIDE_EFFECTS (decl), 0,
! 			  TREE_USED (decl) || DECL_INITIAL (decl) != 0,
! 			  0);
  #else
        put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,
  			  part_mode, TREE_SIDE_EFFECTS (decl), 0,
! 			  TREE_USED (decl) || DECL_INITIAL (decl) != 0,
! 			  0);
        put_reg_into_stack (function, XEXP (reg, 1), part_type, part_mode,
  			  part_mode, TREE_SIDE_EFFECTS (decl), 0,
! 			  TREE_USED (decl) || DECL_INITIAL (decl) != 0,
! 			  0);
  #endif
  
        /* Change the CONCAT into a combined MEM for both parts.  */
*************** put_var_into_stack (decl)
*** 1628,1634 ****
  
  static void
  put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p,
! 		    original_regno, used_p)
       struct function *function;
       rtx reg;
       tree type;
--- 1652,1658 ----
  
  static void
  put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p,
! 		    original_regno, used_p, ht)
       struct function *function;
       rtx reg;
       tree type;
*************** put_reg_into_stack (function, reg, type,
*** 1636,1641 ****
--- 1660,1666 ----
       int volatile_p;
       int original_regno;
       int used_p;
+      struct hash_table *ht;
  {
    rtx new = 0;
    int regno = original_regno;
*************** put_reg_into_stack (function, reg, type,
*** 1698,1711 ****
      }
    else if (used_p)
      /* Variable is local; fix it up now.  */
!     fixup_var_refs (reg, promoted_mode, TREE_UNSIGNED (type));
  }
  
  static void
! fixup_var_refs (var, promoted_mode, unsignedp)
       rtx var;
       enum machine_mode promoted_mode;
       int unsignedp;
  {
    tree pending;
    rtx first_insn = get_insns ();
--- 1723,1737 ----
      }
    else if (used_p)
      /* Variable is local; fix it up now.  */
!     fixup_var_refs (reg, promoted_mode, TREE_UNSIGNED (type), ht);
  }
  
  static void
! fixup_var_refs (var, promoted_mode, unsignedp, ht)
       rtx var;
       enum machine_mode promoted_mode;
       int unsignedp;
+      struct hash_table *ht;
  {
    tree pending;
    rtx first_insn = get_insns ();
*************** fixup_var_refs (var, promoted_mode, unsi
*** 1713,1726 ****
    tree rtl_exps = rtl_expr_chain;
  
    /* Must scan all insns for stack-refs that exceed the limit.  */
!   fixup_var_refs_insns (var, promoted_mode, unsignedp, first_insn, stack == 0);
  
    /* Scan all pending sequences too.  */
    for (; stack; stack = stack->next)
      {
        push_to_sequence (stack->first);
        fixup_var_refs_insns (var, promoted_mode, unsignedp,
! 			    stack->first, stack->next != 0);
        /* Update remembered end of sequence
  	 in case we added an insn at the end.  */
        stack->last = get_last_insn ();
--- 1739,1756 ----
    tree rtl_exps = rtl_expr_chain;
  
    /* Must scan all insns for stack-refs that exceed the limit.  */
!   fixup_var_refs_insns (var, promoted_mode, unsignedp, first_insn, 
! 			stack == 0, ht);
!   /* If there's a hash table, it must record all uses of VAR.  */
!   if (ht)
!     return;
  
    /* Scan all pending sequences too.  */
    for (; stack; stack = stack->next)
      {
        push_to_sequence (stack->first);
        fixup_var_refs_insns (var, promoted_mode, unsignedp,
! 			    stack->first, stack->next != 0, 0);
        /* Update remembered end of sequence
  	 in case we added an insn at the end.  */
        stack->last = get_last_insn ();
*************** fixup_var_refs (var, promoted_mode, unsi
*** 1734,1747 ****
        if (seq != const0_rtx && seq != 0)
  	{
  	  push_to_sequence (seq);
! 	  fixup_var_refs_insns (var, promoted_mode, unsignedp, seq, 0);
  	  end_sequence ();
  	}
      }
  
    /* Scan the catch clauses for exception handling too.  */
    push_to_sequence (catch_clauses);
!   fixup_var_refs_insns (var, promoted_mode, unsignedp, catch_clauses, 0);
    end_sequence ();
  }
  
--- 1764,1779 ----
        if (seq != const0_rtx && seq != 0)
  	{
  	  push_to_sequence (seq);
! 	  fixup_var_refs_insns (var, promoted_mode, unsignedp, seq, 0,
! 				0);
  	  end_sequence ();
  	}
      }
  
    /* Scan the catch clauses for exception handling too.  */
    push_to_sequence (catch_clauses);
!   fixup_var_refs_insns (var, promoted_mode, unsignedp, catch_clauses,
! 			0, 0);
    end_sequence ();
  }
  
*************** find_fixup_replacement (replacements, x)
*** 1777,1791 ****
     main chain of insns for the current function.  */
  
  static void
! fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel)
       rtx var;
       enum machine_mode promoted_mode;
       int unsignedp;
       rtx insn;
       int toplevel;
  {
    rtx call_dest = 0;
  
    while (insn)
      {
        rtx next = NEXT_INSN (insn);
--- 1809,1835 ----
     main chain of insns for the current function.  */
  
  static void
! fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel, ht)
       rtx var;
       enum machine_mode promoted_mode;
       int unsignedp;
       rtx insn;
       int toplevel;
+      struct hash_table *ht;
  {
    rtx call_dest = 0;
+   rtx insn_list;
  
+   /* If we already know which INSNs reference VAR there's no need
+      to walk the entire instruction chain.  */
+   if (ht)
+     {
+       insn_list = ((struct insns_for_mem_entry *) 
+ 		   hash_lookup (ht, var, /*create=*/0, /*copy=*/0))->insns;
+       insn = insn_list ? XEXP (insn_list, 0) : NULL_RTX;
+       insn_list = XEXP (insn_list, 1);
+     }
+ 
    while (insn)
      {
        rtx next = NEXT_INSN (insn);
*************** fixup_var_refs_insns (var, promoted_mode
*** 1957,1963 ****
  	      XEXP (note, 0)
  		= walk_fixup_memory_subreg (XEXP (note, 0), insn, 1);
  	}
!       insn = next;
      }
  }
  
--- 2001,2016 ----
  	      XEXP (note, 0)
  		= walk_fixup_memory_subreg (XEXP (note, 0), insn, 1);
  	}
! 
!       if (!ht)
! 	insn = next;
!       else if (insn_list)
! 	{
! 	  insn = XEXP (insn_list, 0);
! 	  insn_list = XEXP (insn_list, 1);
! 	}
!       else
! 	insn = NULL_RTX;
      }
  }
  
*************** gen_mem_addressof (reg, decl)
*** 2929,2935 ****
    MEM_ALIAS_SET (reg) = get_alias_set (decl);
  
    if (TREE_USED (decl) || DECL_INITIAL (decl) != 0)
!     fixup_var_refs (reg, GET_MODE (reg), TREE_UNSIGNED (type));
  
    return reg;
  }
--- 2982,2988 ----
    MEM_ALIAS_SET (reg) = get_alias_set (decl);
  
    if (TREE_USED (decl) || DECL_INITIAL (decl) != 0)
!     fixup_var_refs (reg, GET_MODE (reg), TREE_UNSIGNED (type), 0);
  
    return reg;
  }
*************** flush_addressof (decl)
*** 2945,2958 ****
        && 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));
  }
  
  /* Force the register pointed to by R, an ADDRESSOF rtx, into the stack.  */
  
  static void
! put_addressof_into_stack (r)
       rtx r;
  {
    tree decl = ADDRESSOF_DECL (r);
    rtx reg = XEXP (r, 0);
--- 2998,3012 ----
        && 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 (r, ht)
       rtx r;
+      struct hash_table *ht;
  {
    tree decl = ADDRESSOF_DECL (r);
    rtx reg = XEXP (r, 0);
*************** put_addressof_into_stack (r)
*** 2963,2969 ****
    put_reg_into_stack (0, reg, TREE_TYPE (decl), GET_MODE (reg),
  		      DECL_MODE (decl), TREE_SIDE_EFFECTS (decl),
  		      ADDRESSOF_REGNO (r),
! 		      TREE_USED (decl) || DECL_INITIAL (decl) != 0);
  }
  
  /* List of replacements made below in purge_addressof_1 when creating
--- 3017,3023 ----
    put_reg_into_stack (0, reg, TREE_TYPE (decl), GET_MODE (reg),
  		      DECL_MODE (decl), TREE_SIDE_EFFECTS (decl),
  		      ADDRESSOF_REGNO (r),
! 		      TREE_USED (decl) || DECL_INITIAL (decl) != 0, ht);
  }
  
  /* List of replacements made below in purge_addressof_1 when creating
*************** static rtx purge_addressof_replacements;
*** 2975,2984 ****
     the stack.  */
  
  static void
! purge_addressof_1 (loc, insn, force, store)
       rtx *loc;
       rtx insn;
       int force, store;
  {
    rtx x;
    RTX_CODE code;
--- 3029,3039 ----
     the stack.  */
  
  static void
! purge_addressof_1 (loc, insn, force, store, ht)
       rtx *loc;
       rtx insn;
       int force, store;
+      struct hash_table *ht;
  {
    rtx x;
    RTX_CODE code;
*************** purge_addressof_1 (loc, insn, force, sto
*** 3032,3038 ****
        if (GET_CODE (sub) == REG
  	  && (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode))
  	{
! 	  put_addressof_into_stack (XEXP (x, 0));
  	  return;
  	}
        else if (GET_CODE (sub) == REG && GET_MODE (x) != GET_MODE (sub))
--- 3087,3093 ----
        if (GET_CODE (sub) == REG
  	  && (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode))
  	{
! 	  put_addressof_into_stack (XEXP (x, 0), ht);
  	  return;
  	}
        else if (GET_CODE (sub) == REG && GET_MODE (x) != GET_MODE (sub))
*************** purge_addressof_1 (loc, insn, force, sto
*** 3111,3117 ****
  
  	      if (store)
  		{
! 		  rtx p;
  
  		  start_sequence ();
  		  val = gen_reg_rtx (GET_MODE (x));
--- 3166,3172 ----
  
  	      if (store)
  		{
! 		  rtx p = PREV_INSN (insn);
  
  		  start_sequence ();
  		  val = gen_reg_rtx (GET_MODE (x));
*************** purge_addressof_1 (loc, insn, force, sto
*** 3125,3130 ****
--- 3180,3187 ----
  		  seq = gen_sequence ();
  		  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),
*************** purge_addressof_1 (loc, insn, force, sto
*** 3143,3152 ****
  
  		  seq = gen_sequence ();
  		  end_sequence ();
! 		  emit_insn_after (seq, insn);
  		}
  	      else
  		{
  		  start_sequence ();
  		  val = extract_bit_field (sub, size_x, 0, 1, NULL_RTX,
  					   GET_MODE (x), GET_MODE (x),
--- 3200,3215 ----
  
  		  seq = gen_sequence ();
  		  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),
*************** purge_addressof_1 (loc, insn, force, sto
*** 3164,3169 ****
--- 3227,3234 ----
  		  seq = gen_sequence ();
  		  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
*************** purge_addressof_1 (loc, insn, force, sto
*** 3192,3204 ****
      }
    else if (code == ADDRESSOF)
      {
!       put_addressof_into_stack (x);
        return;
      }
    else if (code == SET)
      {
!       purge_addressof_1 (&SET_DEST (x), insn, force, 1);
!       purge_addressof_1 (&SET_SRC (x), insn, force, 0);
        return;
      }
  
--- 3257,3269 ----
      }
    else if (code == ADDRESSOF)
      {
!       put_addressof_into_stack (x, ht);
        return;
      }
    else if (code == SET)
      {
!       purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht);
!       purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht);
        return;
      }
  
*************** purge_addressof_1 (loc, insn, force, sto
*** 3207,3219 ****
    for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
      {
        if (*fmt == 'e')
! 	purge_addressof_1 (&XEXP (x, i), insn, force, 0);
        else if (*fmt == 'E')
  	for (j = 0; j < XVECLEN (x, i); j++)
! 	  purge_addressof_1 (&XVECEXP (x, i, j), insn, force, 0);
      }
  }
  
  /* Eliminate all occurrences of ADDRESSOF from INSNS.  Elide any remaining
     (MEM (ADDRESSOF)) patterns, and force any needed registers into the
     stack.  */
--- 3272,3401 ----
    for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
      {
        if (*fmt == 'e')
! 	purge_addressof_1 (&XEXP (x, i), insn, force, 0, ht);
        else if (*fmt == 'E')
  	for (j = 0; j < XVECLEN (x, i); j++)
! 	  purge_addressof_1 (&XVECEXP (x, i, j), insn, force, 0, ht);
!     }
! }
! 
! /* Return a new hash table entry in HT.  */
! 
! static struct hash_entry *
! insns_for_mem_newfunc (he, ht, k)
!      struct hash_entry *he;
!      struct hash_table *ht;
!      hash_table_key k ATTRIBUTE_UNUSED;
! {
!   struct insns_for_mem_entry *ifmhe;
!   if (he)
!     return he;
! 
!   ifmhe = ((struct insns_for_mem_entry *)
! 	   hash_allocate (ht, sizeof (struct insns_for_mem_entry)));
!   ifmhe->insns = NULL_RTX;
! 
!   return &ifmhe->he;
! }
! 
! /* Return a hash value for K, a REG.  */
! 
! static unsigned long
! insns_for_mem_hash (k)
!      hash_table_key k;
! {
!   /* K is really a RTX.  Just use the address as the hash value.  */
!   return (unsigned long) k;
! }
! 
! /* Return non-zero if K1 and K2 (two REGs) are the same.  */
! 
! static boolean
! insns_for_mem_comp (k1, k2)
!      hash_table_key k1;
!      hash_table_key k2;
! {
!   return k1 == k2;
! }
! 
! struct insns_for_mem_walk_info {
!   /* The hash table that we are using to record which INSNs use which
!      MEMs.  */
!   struct hash_table *ht;
! 
!   /* The INSN we are currently proessing.  */
!   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 (r, data)
!      rtx *r;
!      void *data;
! {
!   struct insns_for_mem_walk_info *ifmwi 
!     = (struct insns_for_mem_walk_info *) data;
! 
!   if (ifmwi->pass == 0 && *r && GET_CODE (*r) == ADDRESSOF
!       && GET_CODE (XEXP (*r, 0)) == REG)
!     hash_lookup (ifmwi->ht, XEXP (*r, 0), /*create=*/1, /*copy=*/0);
!   else if (ifmwi->pass == 1 && *r && GET_CODE (*r) == REG)
!     {
!       /* Lookup this MEM in the hashtable, creating it if necessary.  */
!       struct insns_for_mem_entry *ifme 
! 	= (struct insns_for_mem_entry *) hash_lookup (ifmwi->ht,
! 						      *r,
! 						      /*create=*/0,
! 						      /*copy=*/0);
! 
!       /* 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))
! 	{
! 	  /* We do the allocation on the same obstack as is used for
! 	     the hash table since this memory will not be used once
! 	     the hash table is deallocated.  */
! 	  push_obstacks (&ifmwi->ht->memory, &ifmwi->ht->memory);
! 	  ifme->insns = gen_rtx_EXPR_LIST (VOIDmode, ifmwi->insn, 
! 					   ifme->insns);
! 	  pop_obstacks ();
! 	}
      }
+ 
+   return 0;
  }
  
+ /* Walk the INSNS, until we reach LAST_INSN, recording which INSNs use
+    which REGs in HT.  */
+ 
+ static void
+ compute_insns_for_mem (insns, last_insn, ht)
+      rtx insns;
+      rtx last_insn;
+      struct hash_table *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 (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ 	{
+ 	  ifmwi.insn = insn;
+ 	  for_each_rtx (&insn, insns_for_mem_walk, &ifmwi);
+ 	}
+ }
+ 
  /* Eliminate all occurrences of ADDRESSOF from INSNS.  Elide any remaining
     (MEM (ADDRESSOF)) patterns, and force any needed registers into the
     stack.  */
*************** purge_addressof (insns)
*** 3223,3236 ****
       rtx insns;
  {
    rtx insn;
    for (insn = insns; insn; insn = NEXT_INSN (insn))
      if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
  	|| GET_CODE (insn) == CALL_INSN)
        {
  	purge_addressof_1 (&PATTERN (insn), insn,
! 			   asm_noperands (PATTERN (insn)) > 0, 0);
! 	purge_addressof_1 (&REG_NOTES (insn), NULL_RTX, 0, 0);
        }
    purge_addressof_replacements = 0;
  }
  
--- 3405,3436 ----
       rtx insns;
  {
    rtx insn;
+   struct hash_table 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, more 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.  */
+   hash_table_init (&ht, 
+ 		   insns_for_mem_newfunc,
+ 		   insns_for_mem_hash,
+ 		   insns_for_mem_comp);
+   compute_insns_for_mem (insns, NULL_RTX, &ht);
+ 
    for (insn = insns; insn; insn = NEXT_INSN (insn))
      if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
  	|| GET_CODE (insn) == CALL_INSN)
        {
  	purge_addressof_1 (&PATTERN (insn), insn,
! 			   asm_noperands (PATTERN (insn)) > 0, 0, &ht);
! 	purge_addressof_1 (&REG_NOTES (insn), NULL_RTX, 0, 0, &ht);
        }
+ 
+   /* Clean up.  */
+   hash_table_free (&ht);
    purge_addressof_replacements = 0;
  }
  
Index: Makefile.in
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/Makefile.in,v
retrieving revision 1.243
diff -c -p -r1.243 Makefile.in
*** Makefile.in	1999/03/18 21:59:34	1.243
--- Makefile.in	1999/03/23 15:45:13
*************** OBJS = toplev.o version.o tree.o print-t
*** 679,685 ****
   insn-peep.o reorg.o $(SCHED_PREFIX)sched.o final.o recog.o reg-stack.o \
   insn-opinit.o insn-recog.o insn-extract.o insn-output.o insn-emit.o lcm.o \
   profile.o insn-attrtab.o $(out_object_file) getpwd.o $(EXTRA_OBJS) convert.o \
!  mbchar.o dyn-string.o splay-tree.o graph.o sbitmap.o resource.o
  
  # GEN files are listed separately, so they can be built before doing parallel
  #  makes for cc1 or cc1plus.  Otherwise sequent parallel make attempts to load
--- 679,685 ----
   insn-peep.o reorg.o $(SCHED_PREFIX)sched.o final.o recog.o reg-stack.o \
   insn-opinit.o insn-recog.o insn-extract.o insn-output.o insn-emit.o lcm.o \
   profile.o insn-attrtab.o $(out_object_file) getpwd.o $(EXTRA_OBJS) convert.o \
!  mbchar.o dyn-string.o splay-tree.o graph.o sbitmap.o resource.o hash.o
  
  # GEN files are listed separately, so they can be built before doing parallel
  #  makes for cc1 or cc1plus.  Otherwise sequent parallel make attempts to load
*************** varasm.o : varasm.c $(CONFIG_H) system.h
*** 1452,1458 ****
     xcoffout.h output.h c-pragma.h toplev.h except.h dbxout.h sdbout.h
  function.o : function.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h \
     function.h insn-flags.h insn-codes.h $(EXPR_H) $(REGS_H) hard-reg-set.h \
!    insn-config.h $(RECOG_H) output.h toplev.h except.h
  stmt.o : stmt.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h function.h  \
     insn-flags.h insn-config.h insn-codes.h hard-reg-set.h $(EXPR_H) except.h \
     loop.h $(RECOG_H) toplev.h output.h varray.h
--- 1452,1458 ----
     xcoffout.h output.h c-pragma.h toplev.h except.h dbxout.h sdbout.h
  function.o : function.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h \
     function.h insn-flags.h insn-codes.h $(EXPR_H) $(REGS_H) hard-reg-set.h \
!    insn-config.h $(RECOG_H) output.h toplev.h except.h hash.h
  stmt.o : stmt.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h function.h  \
     insn-flags.h insn-config.h insn-codes.h hard-reg-set.h $(EXPR_H) except.h \
     loop.h $(RECOG_H) toplev.h output.h varray.h
Index: cp/Makefile.in
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/Makefile.in,v
retrieving revision 1.47
diff -c -p -r1.47 Makefile.in
*** Makefile.in	1999/03/14 17:43:56	1.47
--- Makefile.in	1999/03/23 15:45:14
*************** CXX_OBJS = call.o decl.o errfn.o expr.o 
*** 191,198 ****
   repo.o @extra_cxx_objs@
  
  # Language-independent object files.
! OBJS = `cat ../stamp-objlist` ../c-common.o ../c-pragma.o ../hash.o
! OBJDEPS = ../stamp-objlist ../c-common.o ../c-pragma.o ../hash.o
  
  compiler: ../cc1plus$(exeext)
  ../cc1plus$(exeext): $(P) $(OBJDEPS) $(CXX_OBJS) $(LIBDEPS)
--- 191,198 ----
   repo.o @extra_cxx_objs@
  
  # Language-independent object files.
! OBJS = `cat ../stamp-objlist` ../c-common.o ../c-pragma.o
! OBJDEPS = ../stamp-objlist ../c-common.o ../c-pragma.o
  
  compiler: ../cc1plus$(exeext)
  ../cc1plus$(exeext): $(P) $(OBJDEPS) $(CXX_OBJS) $(LIBDEPS)



More information about the Gcc-patches mailing list