[CFT] mostly fix opt/2692

Richard Henderson rth@redhat.com
Fri Apr 12 02:02:00 GMT 2002


The largest problem here is lots of inline function calls that take
reference parameters, all of which want to put_var_into_stack.  And
then we were being quite lame about doing that.

The original profile looks like

 expand                : 437.55 (63%) usr   0.06 ( 4%) sys 437.62 (63%) wall
 reload CSE regs       :  93.22 (14%) usr   0.02 ( 1%) sys  93.25 (13%) wall
 global alloc          :  77.21 (11%) usr   0.04 ( 3%) sys  77.25 (11%) wall
 regmove               :  46.49 ( 7%) usr   0.02 ( 1%) sys  46.50 ( 7%) wall
 CSE                   :  11.21 ( 2%) usr   0.02 ( 1%) sys  11.25 ( 2%) wall
 TOTAL                 : 690.08             1.59           697.00

 23.67    177.68   177.68 346184136     0.00     0.00  fixup_var_refs_1
 18.96    320.01   142.34    58977     0.00     0.01  fixup_var_refs_insns
  9.57    391.89    71.88 346184136     0.00     0.00  fixup_var_refs_insn
  8.67    456.94    65.05    17877     0.00     0.00  find_equiv_reg
  6.96    509.17    52.23    19084     0.00     0.00  reg_is_remote_constant_p

Hmm.  Very Suggestive.  Why, yes, we are in fact iterating over the
insns of a very large function a gazillion times.  Mark added some
nice hash-tabley things a while ago, but apparently only changed the
.addressof pass to use it, not initial variable expansion.

So I rearranged things a bit so we queue var refs fixups until the
end of function expansion and set up the hash table and now the
profile looks like

 expand                :   1.29 ( 1%) usr   0.04 ( 2%) sys   1.38 ( 1%) wall
 reload CSE regs       :  88.75 (36%) usr   0.02 ( 1%) sys  88.75 (34%) wall
 global alloc          :  77.34 (31%) usr   0.04 ( 2%) sys  77.38 (30%) wall
 regmove               :  46.00 (18%) usr   0.01 ( 1%) sys  46.00 (18%) wall
 CSE                   :  11.43 ( 5%) usr   0.04 ( 2%) sys  11.62 ( 4%) wall
 TOTAL                 : 249.21             1.86           259.25

 22.84     58.81    58.81    17883     0.00     0.00  find_equiv_reg
 19.87    109.99    51.18    20005     0.00     0.00  reg_is_remote_constant_p
 16.23    151.79    41.80 111292090     0.00     0.00  cselib_invalidate_mem_1

I.e. fixup_var_refs has dropped completely off the map.

It looks very nice on paper.  It'd be a real shame not to have this on
the branch -- if it works.  It's a fairly invasive change to the order
in which things are done, and as such warrents some careful testing.

At this point I've done nothing with this patch but run one file through
it, and even that one I havn't executed.  I'm about to start some overnight
tests and pop off to bed, but I thought I'd encourage some folks living
nearer GMT to test this as well.


r~


	* function.h (struct function): Add fixup_var_refs_queue_p.
	* function.c (push_function_context_to): Don't clear the queue.
	(pop_function_context_from): Don't run the queue.
	(schedule_fixup_var_refs): Rearrange arguments to match
	fixup_var_refs; update all callers.  Queue the fixup if
	fixup_var_refs_queue_p.
	(fixup_var_refs_insns_with_hash): If no hash table entry,
	nothing to do.
	(gen_mem_addressof): Use schedule_fixup_var_refs.
	(prepare_function_start): Set fixup_var_refs_queue_p.
	(fixup_queued_var_refs): New.
	(expand_function_end): Call it.

Index: function.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/function.c,v
retrieving revision 1.347.2.3
diff -c -p -d -r1.347.2.3 function.c
*** function.c	3 Apr 2002 03:43:36 -0000	1.347.2.3
--- function.c	12 Apr 2002 08:38:25 -0000
*************** static void put_reg_into_stack	PARAMS ((
*** 236,244 ****
  					 enum machine_mode, enum machine_mode,
  					 int, unsigned int, int,
  					 struct hash_table *));
! static void schedule_fixup_var_refs PARAMS ((struct function *, rtx, tree,
  					     enum machine_mode,
! 					     struct hash_table *));
  static void fixup_var_refs	PARAMS ((rtx, enum machine_mode, int, rtx,
  					 struct hash_table *));
  static struct fixup_replacement
--- 236,245 ----
  					 enum machine_mode, enum machine_mode,
  					 int, unsigned int, int,
  					 struct hash_table *));
! static void schedule_fixup_var_refs PARAMS ((struct function *, rtx,
  					     enum machine_mode,
! 					     int, struct hash_table *));
! static void fixup_queued_var_refs PARAMS ((void));
  static void fixup_var_refs	PARAMS ((rtx, enum machine_mode, int, rtx,
  					 struct hash_table *));
  static struct fixup_replacement
*************** push_function_context_to (context)
*** 354,360 ****
  
    p->outer = outer_function_chain;
    outer_function_chain = p;
-   p->fixup_var_refs_queue = 0;
  
    if (save_lang_status)
      (*save_lang_status) (p);
--- 355,360 ----
*************** pop_function_context_from (context)
*** 376,382 ****
       tree context ATTRIBUTE_UNUSED;
  {
    struct function *p = outer_function_chain;
-   struct var_refs_queue *queue;
  
    cfun = p;
    outer_function_chain = p->outer;
--- 376,381 ----
*************** pop_function_context_from (context)
*** 389,420 ****
    if (restore_lang_status)
      (*restore_lang_status) (p);
  
-   /* Finish doing put_var_into_stack for any of our variables which became
-      addressable during the nested function.  If only one entry has to be
-      fixed up, just do that one.  Otherwise, first make a list of MEMs that
-      are not to be unshared.  */
-   if (p->fixup_var_refs_queue == 0)
-     ;
-   else if (p->fixup_var_refs_queue->next == 0)
-     fixup_var_refs (p->fixup_var_refs_queue->modified,
- 		    p->fixup_var_refs_queue->promoted_mode,
- 		    p->fixup_var_refs_queue->unsignedp,
- 		    p->fixup_var_refs_queue->modified, 0);
-   else
-     {
-       rtx list = 0;
- 
-       for (queue = p->fixup_var_refs_queue; queue; queue = queue->next)
- 	list = gen_rtx_EXPR_LIST (VOIDmode, queue->modified, list);
- 
-       for (queue = p->fixup_var_refs_queue; queue; queue = queue->next)
- 	fixup_var_refs (queue->modified, queue->promoted_mode,
- 			queue->unsignedp, list, 0);
- 
-     }
- 
-   p->fixup_var_refs_queue = 0;
- 
    /* Reset variables that have known state during rtx generation.  */
    rtx_equal_function_value_matters = 1;
    virtuals_instantiated = 0;
--- 388,393 ----
*************** put_var_into_stack (decl)
*** 1475,1484 ****
  	XEXP (reg, 0) = copy_rtx (XEXP (reg, 0));
        if (usedp)
  	{
! 	  schedule_fixup_var_refs (function, reg, TREE_TYPE (decl),
! 				   promoted_mode, 0);
! 	  schedule_fixup_var_refs (function, lopart, part_type, part_mode, 0);
! 	  schedule_fixup_var_refs (function, hipart, part_type, part_mode, 0);
  	}
      }
    else
--- 1448,1459 ----
  	XEXP (reg, 0) = copy_rtx (XEXP (reg, 0));
        if (usedp)
  	{
! 	  schedule_fixup_var_refs (function, reg, promoted_mode,
! 				   TREE_UNSIGNED (TREE_TYPE (decl)), 0);
! 	  schedule_fixup_var_refs (function, lopart, part_mode,
! 				   TREE_UNSIGNED (part_type), 0);
! 	  schedule_fixup_var_refs (function, hipart, part_mode,
! 				   TREE_UNSIGNED (part_type), 0);
  	}
      }
    else
*************** put_reg_into_stack (function, reg, type,
*** 1537,1543 ****
      }
  
    if (used_p)
!     schedule_fixup_var_refs (function, reg, type, promoted_mode, ht);
  }
  
  /* Make sure that all refs to the variable, previously made
--- 1512,1519 ----
      }
  
    if (used_p)
!     schedule_fixup_var_refs (function, reg, promoted_mode,
! 			     TREE_UNSIGNED (type), ht);
  }
  
  /* Make sure that all refs to the variable, previously made
*************** put_reg_into_stack (function, reg, type,
*** 1545,1565 ****
     See function above for meaning of arguments.  */
  
  static void
! schedule_fixup_var_refs (function, reg, type, promoted_mode, ht)
       struct function *function;
       rtx reg;
-      tree type;
       enum machine_mode promoted_mode;
       struct hash_table *ht;
  {
!   int unsigned_p = type ? TREE_UNSIGNED (type) : 0;
  
!   if (function != 0)
!     {
!       struct var_refs_queue *temp;
  
!       temp
! 	= (struct var_refs_queue *) ggc_alloc (sizeof (struct var_refs_queue));
        temp->modified = reg;
        temp->promoted_mode = promoted_mode;
        temp->unsignedp = unsigned_p;
--- 1521,1542 ----
     See function above for meaning of arguments.  */
  
  static void
! schedule_fixup_var_refs (function, reg, promoted_mode, unsigned_p, ht)
       struct function *function;
       rtx reg;
       enum machine_mode promoted_mode;
+      int unsigned_p;
       struct hash_table *ht;
  {
!   struct var_refs_queue *temp;
  
!   if (function == 0)
!     function = cfun;
  
!   if (function->fixup_var_refs_queue_p)
!     {
!       temp = (struct var_refs_queue *)
! 	ggc_alloc (sizeof (struct var_refs_queue));
        temp->modified = reg;
        temp->promoted_mode = promoted_mode;
        temp->unsignedp = unsigned_p;
*************** schedule_fixup_var_refs (function, reg, 
*** 1567,1583 ****
        function->fixup_var_refs_queue = temp;
      }
    else
-     /* Variable is local; fix it up now.  */
      fixup_var_refs (reg, promoted_mode, unsigned_p, reg, ht);
  }
  
  static void
  fixup_var_refs (var, promoted_mode, unsignedp, may_share, ht)
       rtx var;
       enum machine_mode promoted_mode;
       int unsignedp;
-      struct hash_table *ht;
       rtx may_share;
  {
    tree pending;
    rtx first_insn = get_insns ();
--- 1544,1596 ----
        function->fixup_var_refs_queue = temp;
      }
    else
      fixup_var_refs (reg, promoted_mode, unsigned_p, reg, ht);
  }
+ 
+ /* Finish doing put_var_into_stack for any of our variables which became
+    addressable during compilation.  */
+ 
+ static void
+ fixup_queued_var_refs ()
+ {
+   struct var_refs_queue *queue = cfun->fixup_var_refs_queue;
+ 
+   if (!queue)
+     return;
+ 
+   if (!queue->next)
+     fixup_var_refs (queue->modified, queue->promoted_mode,
+ 		    queue->unsignedp, queue->modified, NULL);
+   else
+     {
+       rtx list;
+       struct hash_table ht;
+ 
+       hash_table_init (&ht, insns_for_mem_newfunc, insns_for_mem_hash,
+ 		       insns_for_mem_comp);
+       compute_insns_for_mem (get_insns (), NULL_RTX, &ht);
+ 
+       list = NULL_RTX;
+       for (queue = cfun->fixup_var_refs_queue; queue; queue = queue->next)
+ 	list = alloc_EXPR_LIST (VOIDmode, queue->modified, list);
+ 
+       for (queue = cfun->fixup_var_refs_queue; queue; queue = queue->next)
+ 	fixup_var_refs (queue->modified, queue->promoted_mode,
+ 			queue->unsignedp, list, &ht);
+ 
+       hash_table_free (&ht);
+     }
+ 
+   cfun->fixup_var_refs_queue = NULL;
+ }
  
  static void
  fixup_var_refs (var, promoted_mode, unsignedp, may_share, ht)
       rtx var;
       enum machine_mode promoted_mode;
       int unsignedp;
       rtx may_share;
+      struct hash_table *ht;
  {
    tree pending;
    rtx first_insn = get_insns ();
*************** fixup_var_refs_insns_with_hash (ht, var,
*** 1723,1728 ****
--- 1736,1744 ----
  						  /*create=*/0, /*copy=*/0);
    rtx insn_list;
  
+   if (!ime)
+     return;
+ 
    for (insn_list = ime->insns; insn_list != 0; insn_list = XEXP (insn_list, 1))
      if (INSN_P (XEXP (insn_list, 0)))
        fixup_var_refs_insn (XEXP (insn_list, 0), var, promoted_mode,
*************** gen_mem_addressof (reg, decl)
*** 2920,2929 ****
  	SET_DECL_RTL (decl, reg);
  
        if (TREE_USED (decl) || (DECL_P (decl) && DECL_INITIAL (decl) != 0))
! 	fixup_var_refs (reg, GET_MODE (reg), TREE_UNSIGNED (type), reg, 0);
      }
    else
!     fixup_var_refs (reg, GET_MODE (reg), 0, reg, 0);
  
    return reg;
  }
--- 2936,2946 ----
  	SET_DECL_RTL (decl, reg);
  
        if (TREE_USED (decl) || (DECL_P (decl) && DECL_INITIAL (decl) != 0))
! 	schedule_fixup_var_refs (0, reg, GET_MODE (reg),
! 				 TREE_UNSIGNED (type), 0);
      }
    else
!     schedule_fixup_var_refs (0, reg, GET_MODE (reg), 0, 0);
  
    return reg;
  }
*************** prepare_function_start ()
*** 6214,6219 ****
--- 6231,6239 ----
    current_function_uses_pic_offset_table = 0;
    current_function_cannot_inline = 0;
  
+   /* Queue addressed variable fixups.  */
+   cfun->fixup_var_refs_queue_p = true;
+ 
    /* We have not yet needed to make a label to jump to for tail-recursion.  */
    tail_recursion_label = 0;
  
*************** expand_function_end (filename, line, end
*** 6851,6856 ****
--- 6871,6880 ----
    while (in_sequence_p ())
      end_sequence ();
  
+   /* Drop addressed variables to memory.  */
+   fixup_queued_var_refs ();
+   cfun->fixup_var_refs_queue_p = false;
+ 
    /* Outside function body, can't compute type's actual size
       until next function's body starts.  */
    immediate_size_expand--;
*************** mark_function_status (p)
*** 7947,7953 ****
      {
        ggc_mark (q);
        ggc_mark_rtx (q->modified);
!       }
  
    ggc_mark_rtx (p->x_nonlocal_goto_handler_slots);
    ggc_mark_rtx (p->x_nonlocal_goto_handler_labels);
--- 7971,7977 ----
      {
        ggc_mark (q);
        ggc_mark_rtx (q->modified);
!     }
  
    ggc_mark_rtx (p->x_nonlocal_goto_handler_slots);
    ggc_mark_rtx (p->x_nonlocal_goto_handler_labels);
Index: function.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/function.h,v
retrieving revision 1.75
diff -c -p -d -r1.75 function.h
*** function.h	3 Jan 2002 17:39:59 -0000	1.75
--- function.h	12 Apr 2002 08:38:25 -0000
*************** struct function
*** 475,480 ****
--- 475,483 ----
  
    /* Nonzero if code to initialize arg_pointer_save_area has been emited.  */
    unsigned int arg_pointer_save_area_init : 1;
+ 
+   /* Nonzero if addressable variable fixups should be queued.  */
+   unsigned int fixup_var_refs_queue_p : 1;
  };
  
  /* The function currently being compiled.  */



More information about the Gcc-patches mailing list