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]
Other format: [Raw text]

[patch] Huge reduction of memory usage by var-tracking.c (PR/14362)


Hello,

when variable has the same location(s) in many blocks the information
(struct variable) is uselessly copied many times.
This patch reduces the memory usage of var-tracking.c by sharing
structs variable if they are the same. The number of structs variable
allocated is reduced 1000 times when compiling the testcase from
PR/14362.
The patch also causes some speedup because of not copying these structs.

Bootstrapped/regtested x86-64 and ia64.

Josef

2004-03-08  Josef Zlomek  <zlomekj@suse.cz>

	PR/14362
	* var-tracking.c (struct variable_def): Added field refcount.
	(variable_htab_free): Decrease the refcount and delete variable
	only if there are no more references.
	(unshare_variable): New function.
	(vars_copy_1): Increase refcount instead of copying the variable.
	(variable_union): Share the variables where possible, unshare
	the variables if needed.
	(variable_different_p): Return false if var1 and var2 are
	the same structure.
	(variable_was_changed): Init the refcount of new variable.
	(set_frame_base_location): Unshare variable if needed.
	(set_variable_part): Init the refcount of new variable.
	Unshare the variables if needed.
	(delete_variable_part): Unshare the variables if needed.
	(emit_notes_for_differences_1): Init the refcount of new variable.
	(vt_add_function_parameters): Do not add function parameters to
	IN set of ENTRY_BLOCK_PTR because it is unused anyway.
	(vt_initialize): Do not add frame_base_decl to IN set of
	ENTRY_BLOCK_PTR because it is unused anyway.

Index: var-tracking.c
===================================================================
RCS file: /cvs/gcc-cvs/gcc/gcc/var-tracking.c,v
retrieving revision 2.8
diff -c -p -c -3 -p -r2.8 var-tracking.c
*** var-tracking.c	4 Mar 2004 14:17:29 -0000	2.8
--- var-tracking.c	7 Mar 2004 15:23:18 -0000
*************** typedef struct variable_def
*** 233,238 ****
--- 233,241 ----
    /* The declaration of the variable.  */
    tree decl;
  
+   /* Reference count.  */
+   int refcount;
+ 
    /* Number of variable parts.  */
    int n_var_parts;
  
*************** static void attrs_list_copy (attrs *, at
*** 285,290 ****
--- 288,294 ----
  static void attrs_list_union (attrs *, attrs);
  
  static void vars_clear (htab_t);
+ static variable unshare_variable (dataflow_set *set, variable var);
  static int vars_copy_1 (void **, void *);
  static void vars_copy (htab_t, htab_t);
  static void var_reg_delete_and_set (dataflow_set *, rtx);
*************** variable_htab_free (void *elem)
*** 629,634 ****
--- 633,647 ----
    variable var = (variable) elem;
    location_chain node, next;
  
+ #ifdef ENABLE_CHECKING
+   if (var->refcount <= 0)
+     abort ();
+ #endif
+ 
+   var->refcount--;
+   if (var->refcount > 0)
+     return;
+ 
    for (i = 0; i < var->n_var_parts; i++)
      {
        for (node = var->var_part[i].loc_chain; node; node = next)
*************** vars_clear (htab_t vars)
*** 732,762 ****
    htab_empty (vars);
  }
  
! /* Copy one variable from *SLOT to hash table DATA.  */
  
! static int
! vars_copy_1 (void **slot, void *data)
  {
!   htab_t dst = (htab_t) data;
!   variable src, *dstp, var;
    int i;
  
!   src = *(variable *) slot;
!   dstp = (variable *) htab_find_slot_with_hash (dst, src->decl,
! 						VARIABLE_HASH_VAL (src->decl),
! 						INSERT);
!   var = pool_alloc (var_pool);
!   var->decl = src->decl;
!   var->n_var_parts = src->n_var_parts;
!   *dstp = (void *) var;
  
    for (i = 0; i < var->n_var_parts; i++)
      {
!       location_chain last, node;
  
!       var->var_part[i].offset = src->var_part[i].offset;
!       last = NULL;
!       for (node = src->var_part[i].loc_chain; node; node = node->next)
  	{
  	  location_chain new_lc;
  
--- 745,773 ----
    htab_empty (vars);
  }
  
! /* Return a copy of a variable VAR and insert it to dataflow set SET.  */
  
! static variable
! unshare_variable (dataflow_set *set, variable var)
  {
!   void **slot;
!   variable new_var;
    int i;
  
!   new_var = pool_alloc (var_pool);
!   new_var->decl = var->decl;
!   new_var->refcount = 1;
!   var->refcount--;
!   new_var->n_var_parts = var->n_var_parts;
  
    for (i = 0; i < var->n_var_parts; i++)
      {
!       location_chain node;
!       location_chain *dest;
  
!       new_var->var_part[i].offset = var->var_part[i].offset;
!       dest = &new_var->var_part[i].loc_chain;
!       for (node = var->var_part[i].loc_chain; node; node = node->next)
  	{
  	  location_chain new_lc;
  
*************** vars_copy_1 (void **slot, void *data)
*** 764,784 ****
  	  new_lc->next = NULL;
  	  new_lc->loc = node->loc;
  
! 	  if (last)
! 	    last->next = new_lc;
! 	  else
! 	    var->var_part[i].loc_chain = new_lc;
! 	  last = new_lc;
  	}
  
        /* We are at the basic block boundary when copying variable description
  	 so set the CUR_LOC to be the first element of the chain.  */
!       if (var->var_part[i].loc_chain)
! 	var->var_part[i].cur_loc = var->var_part[i].loc_chain->loc;
        else
! 	var->var_part[i].cur_loc = NULL;
      }
  
    /* Continue traversing the hash table.  */
    return 1;
  }
--- 775,816 ----
  	  new_lc->next = NULL;
  	  new_lc->loc = node->loc;
  
! 	  *dest = new_lc;
! 	  dest = &new_lc->next;
  	}
  
        /* We are at the basic block boundary when copying variable description
  	 so set the CUR_LOC to be the first element of the chain.  */
!       if (new_var->var_part[i].loc_chain)
! 	new_var->var_part[i].cur_loc = new_var->var_part[i].loc_chain->loc;
        else
! 	new_var->var_part[i].cur_loc = NULL;
      }
  
+   slot = htab_find_slot_with_hash (set->vars, new_var->decl,
+ 				   VARIABLE_HASH_VAL (new_var->decl),
+ 				   INSERT);
+   *slot = new_var;
+   return new_var;
+ }
+ 
+ /* Add a variable from *SLOT to hash table DATA and increase its reference
+    count.  */
+ 
+ static int
+ vars_copy_1 (void **slot, void *data)
+ {
+   htab_t dst = (htab_t) data;
+   variable src, *dstp;
+ 
+   src = *(variable *) slot;
+   src->refcount++;
+ 
+   dstp = (variable *) htab_find_slot_with_hash (dst, src->decl,
+ 						VARIABLE_HASH_VAL (src->decl),
+ 						INSERT);
+   *dstp = src;
+ 
    /* Continue traversing the hash table.  */
    return 1;
  }
*************** variable_union (void **slot, void *data)
*** 978,986 ****
  						INSERT);
    if (!*dstp)
      {
!       *dstp = dst = pool_alloc (var_pool);
!       dst->decl = src->decl;
!       dst->n_var_parts = 0;
      }
    else
      dst = *dstp;
--- 1010,1046 ----
  						INSERT);
    if (!*dstp)
      {
!       src->refcount++;
! 
!       /* If CUR_LOC of some variable part is not the first element of
! 	 the location chain we are going to change it so we have to make
! 	 a copy of the variable.  */
!       for (k = 0; k < src->n_var_parts; k++)
! 	{
! 	  if (src->var_part[k].loc_chain)
! 	    {
! #ifdef ENABLE_CHECKING
! 	      if (src->var_part[k].cur_loc == NULL)
! 		abort ();
! #endif
! 	      if (src->var_part[k].cur_loc != src->var_part[k].loc_chain->loc)
! 		break;
! 	    }
! #ifdef ENABLE_CHECKING
! 	  else
! 	    {
! 	      if (src->var_part[k].cur_loc != NULL)
! 		abort ();
! 	    }
! #endif
! 	}
!       if (k < src->n_var_parts)
! 	unshare_variable (set, src);
!       else
! 	*dstp = src;
! 
!       /* Continue traversing the hash table.  */
!       return 1;
      }
    else
      dst = *dstp;
*************** variable_union (void **slot, void *data)
*** 1004,1013 ****
        else
  	j++;
      }
!   if (i < src->n_var_parts)
!     k += src->n_var_parts - i;
!   if (j < dst->n_var_parts)
!     k += dst->n_var_parts - j;
  #ifdef ENABLE_CHECKING
    /* We track only variables whose size is <= MAX_VAR_PARTS bytes
       thus there are at most MAX_VAR_PARTS different offsets.  */
--- 1064,1071 ----
        else
  	j++;
      }
!   k += src->n_var_parts - i;
!   k += dst->n_var_parts - j;
  #ifdef ENABLE_CHECKING
    /* We track only variables whose size is <= MAX_VAR_PARTS bytes
       thus there are at most MAX_VAR_PARTS different offsets.  */
*************** variable_union (void **slot, void *data)
*** 1015,1027 ****
      abort ();
  #endif
  
    i = src->n_var_parts - 1;
    j = dst->n_var_parts - 1;
    dst->n_var_parts = k;
  
    for (k--; k >= 0; k--)
      {
!       location_chain node;
  
        if (i >= 0 && j >= 0
  	  && src->var_part[i].offset == dst->var_part[j].offset)
--- 1073,1088 ----
      abort ();
  #endif
  
+   if (dst->refcount > 1 && dst->n_var_parts != k)
+     dst = unshare_variable (set, dst);
+ 
    i = src->n_var_parts - 1;
    j = dst->n_var_parts - 1;
    dst->n_var_parts = k;
  
    for (k--; k >= 0; k--)
      {
!       location_chain node, node2;
  
        if (i >= 0 && j >= 0
  	  && src->var_part[i].offset == dst->var_part[j].offset)
*************** variable_union (void **slot, void *data)
*** 1032,1038 ****
  	  int dst_l, src_l;
  	  int ii, jj, n;
  	  struct variable_union_info *vui;
! 	  
  	  src_l = 0;
  	  for (node = src->var_part[i].loc_chain; node; node = node->next)
  	    src_l++;
--- 1093,1118 ----
  	  int dst_l, src_l;
  	  int ii, jj, n;
  	  struct variable_union_info *vui;
! 
! 	  /* If DST is shared compare the location chains.
! 	     If they are different we will modify the chain in DST with
! 	     high probability so make a copy of DST.  */
! 	  if (dst->refcount > 1)
! 	    {
! 	      for (node = src->var_part[i].loc_chain,
! 		   node2 = dst->var_part[j].loc_chain; node && node2;
! 		   node = node->next, node2 = node2->next)
! 		{
! 		  if (!((GET_CODE (node2->loc) == REG
! 			 && GET_CODE (node->loc) == REG
! 			 && REGNO (node2->loc) == REGNO (node->loc))
! 			|| rtx_equal_p (node2->loc, node->loc)))
! 		    break;
! 		}
! 	      if (node || node2)
! 		dst = unshare_variable (set, dst);
! 	    }
! 
  	  src_l = 0;
  	  for (node = src->var_part[i].loc_chain; node; node = node->next)
  	    src_l++;
*************** variable_different_p (variable var1, var
*** 1195,1200 ****
--- 1275,1283 ----
  {
    int i;
  
+   if (var1 == var2)
+     return false;
+ 
    if (var1->n_var_parts != var2->n_var_parts)
      return true;
  
*************** variable_was_changed (variable var, htab
*** 1799,1804 ****
--- 1882,1888 ----
  
  	  empty_var = pool_alloc (var_pool);
  	  empty_var->decl = var->decl;
+ 	  empty_var->refcount = 1;
  	  empty_var->n_var_parts = 0;
  	  *slot = empty_var;
  
*************** set_frame_base_location (dataflow_set *s
*** 1851,1857 ****
--- 1935,1946 ----
      abort ();
  #endif
  
+   /* If frame_base_decl is shared unshare it first.  */
+   if (var->refcount > 1)
+     var = unshare_variable (set, var);
+ 
    var->var_part[0].loc_chain->loc = loc;
+   var->var_part[0].cur_loc = loc;
    variable_was_changed (var, set->vars);
  }
  
*************** set_variable_part (dataflow_set *set, rt
*** 1874,1879 ****
--- 1963,1969 ----
        /* Create new variable information.  */
        var = pool_alloc (var_pool);
        var->decl = decl;
+       var->refcount = 1;
        var->n_var_parts = 1;
        var->var_part[0].offset = offset;
        var->var_part[0].loc_chain = NULL;
*************** set_variable_part (dataflow_set *set, rt
*** 1898,1906 ****
  	}
        pos = low;
  
!       if (pos == var->n_var_parts || var->var_part[pos].offset != offset)
  	{
! 	  /* We have not find the location part, new one will be created.  */
  
  #ifdef ENABLE_CHECKING
  	  /* We track only variables whose size is <= MAX_VAR_PARTS bytes
--- 1988,2020 ----
  	}
        pos = low;
  
!       if (pos < var->n_var_parts && var->var_part[pos].offset == offset)
  	{
! 	  node = var->var_part[pos].loc_chain;
! 
! 	  if (node
! 	      && ((GET_CODE (node->loc) == REG && GET_CODE (loc) == REG
! 		   && REGNO (node->loc) == REGNO (loc))
! 		  || rtx_equal_p (node->loc, loc)))
! 	    {
! 	      /* LOC is in the beginning of the chain so we have nothing
! 		 to do.  */
! 	      return;
! 	    }
! 	  else
! 	    {
! 	      /* We have to make a copy of a shared variable.  */
! 	      if (var->refcount > 1)
! 		var = unshare_variable (set, var);
! 	    }
! 	}
!       else
! 	{
! 	  /* We have not found the location part, new one will be created.  */
! 
! 	  /* We have to make a copy of the shared variable.  */
! 	  if (var->refcount > 1)
! 	    var = unshare_variable (set, var);
  
  #ifdef ENABLE_CHECKING
  	  /* We track only variables whose size is <= MAX_VAR_PARTS bytes
*************** set_variable_part (dataflow_set *set, rt
*** 1921,1927 ****
  	}
      }
  
!   /* Delete the location from list.  */
    prev = NULL;
    for (node = var->var_part[pos].loc_chain; node; node = next)
      {
--- 2035,2041 ----
  	}
      }
  
!   /* Delete the location from the list.  */
    prev = NULL;
    for (node = var->var_part[pos].loc_chain; node; node = next)
      {
*************** delete_variable_part (dataflow_set *set,
*** 1990,1995 ****
--- 2104,2126 ----
  	  location_chain node, prev, next;
  	  bool changed;
  
+ 	  if (var->refcount > 1)
+ 	    {
+ 	      /* If the variable contains the location part we have to
+ 		 make a copy of the variable.  */
+ 	      for (node = var->var_part[pos].loc_chain; node;
+ 		   node = node->next)
+ 		{
+ 		  if ((GET_CODE (node->loc) == REG && GET_CODE (loc) == REG
+ 		       && REGNO (node->loc) == REGNO (loc))
+ 		      || rtx_equal_p (node->loc, loc))
+ 		    {
+ 		      var = unshare_variable (set, var);
+ 		      break;
+ 		    }
+ 		}
+ 	    }
+ 
  	  /* Delete the location part.  */
  	  prev = NULL;
  	  for (node = var->var_part[pos].loc_chain; node; node = next)
*************** emit_notes_for_differences_1 (void **slo
*** 2161,2166 ****
--- 2292,2298 ----
  
        empty_var = pool_alloc (var_pool);
        empty_var->decl = old_var->decl;
+       empty_var->refcount = 1;
        empty_var->n_var_parts = 0;
        variable_was_changed (empty_var, NULL);
      }
*************** vt_add_function_parameters (void)
*** 2369,2375 ****
        rtx incoming = DECL_INCOMING_RTL (parm);
        tree decl;
        HOST_WIDE_INT offset;
!       dataflow_set *in, *out;
  
        if (TREE_CODE (parm) != PARM_DECL)
  	continue;
--- 2501,2507 ----
        rtx incoming = DECL_INCOMING_RTL (parm);
        tree decl;
        HOST_WIDE_INT offset;
!       dataflow_set *out;
  
        if (TREE_CODE (parm) != PARM_DECL)
  	continue;
*************** vt_add_function_parameters (void)
*** 2398,2404 ****
        incoming = eliminate_regs (incoming, 0, NULL_RTX);
        if (!frame_pointer_needed && GET_CODE (incoming) == MEM)
  	incoming = adjust_stack_reference (incoming, -stack_adjust);
-       in = &VTI (ENTRY_BLOCK_PTR)->in;
        out = &VTI (ENTRY_BLOCK_PTR)->out;
  
        if (GET_CODE (incoming) == REG)
--- 2530,2535 ----
*************** vt_add_function_parameters (void)
*** 2407,2422 ****
  	  if (REGNO (incoming) >= FIRST_PSEUDO_REGISTER)
  	    abort ();
  #endif
- 	  attrs_list_insert (&in->regs[REGNO (incoming)],
- 			     parm, offset, incoming);
  	  attrs_list_insert (&out->regs[REGNO (incoming)],
  			     parm, offset, incoming);
- 	  set_variable_part (in, incoming, parm, offset);
  	  set_variable_part (out, incoming, parm, offset);
  	}
        else if (GET_CODE (incoming) == MEM)
  	{
- 	  set_variable_part (in, incoming, parm, offset);
  	  set_variable_part (out, incoming, parm, offset);
  	}
      }
--- 2538,2549 ----
*************** vt_initialize (void)
*** 2576,2582 ****
  
        /* Set its initial "location".  */
        base = gen_rtx_MEM (Pmode, stack_pointer_rtx);
-       set_variable_part (&VTI (ENTRY_BLOCK_PTR)->in, base, frame_base_decl, 0);
        set_variable_part (&VTI (ENTRY_BLOCK_PTR)->out, base, frame_base_decl, 0);
      }
    else
--- 2703,2708 ----


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