[kill-loop] Fix a quadratic bottleneck in loop-unroll

Steven Bosscher stevenb@suse.de
Thu Aug 4 13:38:00 GMT 2005


Hi Zdenek, all,

This patch fixes a problem with -fvariable-expansion-in-unroller.  The
algorithm to analyze instructions was quadratic.  Fixed by letting df.c
do the data flow beforehand.  I have bootstrapped and tested this patch
with "-O2 -funroll{,-all}-loops -fvariable-expansion-in-unroller" on
x86_64-unknown-linux-gnu.  Zdenek, does the patch look good to you?

Gr.
Steven

	* loop-unroll.c: Don't include varray.h.  Include df.h.
	(referenced_in_one_insn_in_loop_p): Rewrite to use a df object.
	(analyze_insn_to_expand_var): Take a df object as an argument.
	(analyze_insns_in_loop): When expanding accumulators, compute
	a df object for the loop.  Pass it to analyze_insn_to_expand_var.

Index: loop-unroll.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/loop-unroll.c,v
retrieving revision 1.37
diff -u -3 -p -w -r1.37 loop-unroll.c
--- loop-unroll.c	3 Aug 2005 13:34:35 -0000	1.37
+++ loop-unroll.c	4 Aug 2005 13:32:19 -0000
@@ -33,7 +33,7 @@ Software Foundation, 51 Franklin Street,
 #include "expr.h"
 #include "hashtab.h"
 #include "recog.h"    
-#include "varray.h"                        
+#include "df.h"
 
 /* This pass performs loop unrolling and peeling.  We only perform these
    optimizations on innermost loops (with single exception) because
@@ -135,9 +135,6 @@ static struct opt_info *analyze_insns_in
 static void opt_info_start_duplication (struct opt_info *);
 static void apply_opt_in_copies (struct opt_info *, unsigned, bool, bool);
 static void free_opt_info (struct opt_info *);
-static struct var_to_expand *analyze_insn_to_expand_var (struct loop*, rtx);
-static bool referenced_in_one_insn_in_loop_p (struct loop *, rtx);
-static struct iv_to_split *analyze_iv_to_split_insn (rtx);
 static void expand_var_during_unrolling (struct var_to_expand *, rtx);
 static int insert_var_expansion_initialization (void **, void *);
 static int combine_var_copies_in_loop_exit (void **, void *);
@@ -1509,28 +1506,41 @@ ve_info_eq (const void *ivts1, const voi
   return i1->insn == i2->insn;
 }
 
-/* Returns true if REG is referenced in one insn in LOOP.  */
+/* Returns true if REG is referenced in one insn in LOOP.  We really only have
+   to look at the dataflow object DF created for the loop.  */
 
-bool
-referenced_in_one_insn_in_loop_p (struct loop *loop, rtx reg)
-{
-  basic_block *body, bb;
-  unsigned i;
-  int count_ref = 0;
-  rtx insn;
-  
-  body = get_loop_body (loop); 
-  for (i = 0; i < loop->num_nodes; i++)
-    {
-      bb = body[i];
+static bool
+referenced_in_one_insn_in_loop_p (struct loop *loop ATTRIBUTE_UNUSED,
+				  rtx reg,
+				  struct df *df)
+{
+  struct df_link *link;
+  struct reg_info *reg_info;
+  rtx insn = NULL;
+
+  reg_info = df->regs;
+
+  /* Is there more than one insn definint REG?  */
+  for (link = reg_info[REGNO (reg)].defs; link; link = link->next)
+    {
+      struct ref *ref = link->ref;
+      if (!insn)
+	insn = DF_REF_INSN (ref);
+      else if (insn != DF_REF_INSN (ref))
+	return false;
+    }
       
-      FOR_BB_INSNS (bb, insn)
+  /* Is there more than one insn that uses REG?  */
+  for (link = reg_info[REGNO (reg)].uses; link; link = link->next)
       {
-        if (rtx_referenced_p (reg, insn))
-          count_ref++;
-      }
+      struct ref *ref = link->ref;
+      if (!insn)
+	insn = DF_REF_INSN (ref);
+      else if (insn != DF_REF_INSN (ref))
+	return false;
     }
-  return (count_ref  == 1);
+
+  return true;
 }
 
 /* Determine whether INSN contains an accumulator
@@ -1557,7 +1567,7 @@ referenced_in_one_insn_in_loop_p (struct
 */
 
 static struct var_to_expand *
-analyze_insn_to_expand_var (struct loop *loop, rtx insn)
+analyze_insn_to_expand_var (struct loop *loop, rtx insn, struct df *df)
 {
   rtx set, dest, src, op1;
   struct var_to_expand *ves;
@@ -1588,7 +1598,7 @@ analyze_insn_to_expand_var (struct loop 
   if (!rtx_equal_p (dest, op1))
     return NULL;      
   
-  if (!referenced_in_one_insn_in_loop_p (loop, dest))
+  if (!referenced_in_one_insn_in_loop_p (loop, dest, df))
     return NULL;
   
   if (rtx_referenced_p (dest, XEXP (src, 1)))
@@ -1694,6 +1704,7 @@ analyze_insns_in_loop (struct loop *loop
   PTR *slot2;
   edge *edges = get_loop_exit_edges (loop, &num_edges);
   bool can_apply = false;
+  struct df *df = NULL;
   
   iv_analysis_loop_init (loop);
 
@@ -1719,10 +1730,25 @@ analyze_insns_in_loop (struct loop *loop
       can_apply = true;
     }
   
-  if (flag_variable_expansion_in_unroller
-      && can_apply)
+  if (can_apply && flag_variable_expansion_in_unroller)
+    {
+      bitmap blocks = BITMAP_ALLOC (NULL);
+      for (i = 0; i < loop->num_nodes; i++)
+	bitmap_set_bit (blocks, body[i]->index);
+
+      df = df_init ();
+      df_analyze_subcfg (df, blocks, DF_RD_CHAIN
+				     | DF_RU_CHAIN
+				     | DF_HARD_REGS
+				     | DF_EQUIV_NOTES);
+
+      BITMAP_FREE (blocks);
+
     opt_info->insns_with_var_to_expand = htab_create (5 * loop->num_nodes,
-						      ve_info_hash, ve_info_eq, free);
+							ve_info_hash,
+							ve_info_eq,
+							free);
+    }
   
   for (i = 0; i < loop->num_nodes; i++)
     {
@@ -1746,7 +1772,7 @@ analyze_insns_in_loop (struct loop *loop
           }
         
         if (opt_info->insns_with_var_to_expand)
-          ves = analyze_insn_to_expand_var (loop, insn);
+          ves = analyze_insn_to_expand_var (loop, insn, df);
         
         if (ves)
           {
@@ -1758,6 +1784,10 @@ analyze_insns_in_loop (struct loop *loop
   
   free (edges);
   free (body);
+
+  if (df)
+    df_finish (df);
+
   return opt_info;
 }
 



More information about the Gcc-patches mailing list