This finally limits the number of alias queries we do when looking
for redundant loads/stores from inside SCCVN (thus FRE and PRE).
Previously the number was bound roughly by O(n_loads  * n_stores) while
now it is bound by O(n_loads) with the constant factor
--param sccvn-max-alias-queries-per-access.  The patch should not
make any difference for any real-world testcase but SCCVN compile-time for
half of the artificial testcase in PR46590 goes down
from 230s to 13s.

I'm not sure limiting the walks more is necessary (we hit this
issue only for machine-generated code like this - where other
passes have similar issues, like loop header copying for this
particular case)

Bootstrapped on x86_64-unknown-linux-gnu, testing in progress.

Richard.

2012-08-22  Richard Guenther  <rguent...@suse.de>

        PR tree-optimization/46590
        * tree-ssa-alias.h (get_continuation_for_phi): Add alias query
        counter output argument.
        (walk_non_aliased_vuses): Add alias query counter argument
        to the walker callback.
        * tree-ssa-alias.c (maybe_skip_until): Add alias query counter
        output argument and count alias queries.
        (get_continuation_for_phi_1): Likewise.
        (get_continuation_for_phi): Likewise.
        (walk_non_aliased_vuses): Add alias query counter argument
        to the walker callback and allow it to abort the walk by
        returning -1.
        * tree-ssa-pre.c (translate_vuse_through_block): Adjust.
        * tree-ssa-sccvn.c (vn_reference_lookup_2): Add alias query
        counter parmeter, abort walk if that is bigger than
        --param sccvn-max-alias-queries-per-access.
        * params.def (sccvn-max-alias-queries-per-access): New param.
        * doc/invoke.texi (sccvn-max-alias-queries-per-access): Document.

Index: gcc/tree-ssa-alias.c
===================================================================
*** gcc/tree-ssa-alias.c.orig   2012-08-21 16:46:21.000000000 +0200
--- gcc/tree-ssa-alias.c        2012-08-22 13:38:45.502016867 +0200
*************** stmt_kills_ref_p (gimple stmt, tree ref)
*** 1929,1935 ****
  
  static bool
  maybe_skip_until (gimple phi, tree target, ao_ref *ref,
!                 tree vuse, bitmap *visited)
  {
    basic_block bb = gimple_bb (phi);
  
--- 1929,1935 ----
  
  static bool
  maybe_skip_until (gimple phi, tree target, ao_ref *ref,
!                 tree vuse, unsigned int *cnt, bitmap *visited)
  {
    basic_block bb = gimple_bb (phi);
  
*************** maybe_skip_until (gimple phi, tree targe
*** 1948,1962 ****
          /* An already visited PHI node ends the walk successfully.  */
          if (bitmap_bit_p (*visited, SSA_NAME_VERSION (PHI_RESULT (def_stmt))))
            return true;
!         vuse = get_continuation_for_phi (def_stmt, ref, visited);
          if (!vuse)
            return false;
          continue;
        }
!       /* A clobbering statement or the end of the IL ends it failing.  */
!       else if (gimple_nop_p (def_stmt)
!              || stmt_may_clobber_ref_p_1 (def_stmt, ref))
        return false;
        /* If we reach a new basic-block see if we already skipped it
           in a previous walk that ended successfully.  */
        if (gimple_bb (def_stmt) != bb)
--- 1948,1967 ----
          /* An already visited PHI node ends the walk successfully.  */
          if (bitmap_bit_p (*visited, SSA_NAME_VERSION (PHI_RESULT (def_stmt))))
            return true;
!         vuse = get_continuation_for_phi (def_stmt, ref, cnt, visited);
          if (!vuse)
            return false;
          continue;
        }
!       else if (gimple_nop_p (def_stmt))
        return false;
+       else
+       {
+         /* A clobbering statement or the end of the IL ends it failing.  */
+         ++*cnt;
+         if (stmt_may_clobber_ref_p_1 (def_stmt, ref))
+           return false;
+       }
        /* If we reach a new basic-block see if we already skipped it
           in a previous walk that ended successfully.  */
        if (gimple_bb (def_stmt) != bb)
*************** maybe_skip_until (gimple phi, tree targe
*** 1976,1982 ****
  
  static tree
  get_continuation_for_phi_1 (gimple phi, tree arg0, tree arg1,
!                           ao_ref *ref, bitmap *visited)
  {
    gimple def0 = SSA_NAME_DEF_STMT (arg0);
    gimple def1 = SSA_NAME_DEF_STMT (arg1);
--- 1981,1987 ----
  
  static tree
  get_continuation_for_phi_1 (gimple phi, tree arg0, tree arg1,
!                           ao_ref *ref, unsigned int *cnt, bitmap *visited)
  {
    gimple def0 = SSA_NAME_DEF_STMT (arg0);
    gimple def1 = SSA_NAME_DEF_STMT (arg1);
*************** get_continuation_for_phi_1 (gimple phi,
*** 1989,2002 ****
               && dominated_by_p (CDI_DOMINATORS,
                                  gimple_bb (def1), gimple_bb (def0))))
      {
!       if (maybe_skip_until (phi, arg0, ref, arg1, visited))
        return arg0;
      }
    else if (gimple_nop_p (def1)
           || dominated_by_p (CDI_DOMINATORS,
                              gimple_bb (def0), gimple_bb (def1)))
      {
!       if (maybe_skip_until (phi, arg1, ref, arg0, visited))
        return arg1;
      }
    /* Special case of a diamond:
--- 1994,2007 ----
               && dominated_by_p (CDI_DOMINATORS,
                                  gimple_bb (def1), gimple_bb (def0))))
      {
!       if (maybe_skip_until (phi, arg0, ref, arg1, cnt, visited))
        return arg0;
      }
    else if (gimple_nop_p (def1)
           || dominated_by_p (CDI_DOMINATORS,
                              gimple_bb (def0), gimple_bb (def1)))
      {
!       if (maybe_skip_until (phi, arg1, ref, arg0, cnt, visited))
        return arg1;
      }
    /* Special case of a diamond:
*************** get_continuation_for_phi_1 (gimple phi,
*** 2015,2020 ****
--- 2020,2026 ----
    else if ((common_vuse = gimple_vuse (def0))
           && common_vuse == gimple_vuse (def1))
      {
+       *cnt += 2;
        if (!stmt_may_clobber_ref_p_1 (def0, ref)
          && !stmt_may_clobber_ref_p_1 (def1, ref))
        return common_vuse;
*************** get_continuation_for_phi_1 (gimple phi,
*** 2027,2037 ****
  /* Starting from a PHI node for the virtual operand of the memory reference
     REF find a continuation virtual operand that allows to continue walking
     statements dominating PHI skipping only statements that cannot possibly
!    clobber REF.  Returns NULL_TREE if no suitable virtual operand can
!    be found.  */
  
  tree
! get_continuation_for_phi (gimple phi, ao_ref *ref, bitmap *visited)
  {
    unsigned nargs = gimple_phi_num_args (phi);
  
--- 2033,2044 ----
  /* Starting from a PHI node for the virtual operand of the memory reference
     REF find a continuation virtual operand that allows to continue walking
     statements dominating PHI skipping only statements that cannot possibly
!    clobber REF.  Increments *CNT for each alias disambiguation done.
!    Returns NULL_TREE if no suitable virtual operand can be found.  */
  
  tree
! get_continuation_for_phi (gimple phi, ao_ref *ref,
!                         unsigned int *cnt, bitmap *visited)
  {
    unsigned nargs = gimple_phi_num_args (phi);
  
*************** get_continuation_for_phi (gimple phi, ao
*** 2068,2074 ****
        for (i = 0; i < nargs; ++i)
        {
          arg1 = PHI_ARG_DEF (phi, i);
!         arg0 = get_continuation_for_phi_1 (phi, arg0, arg1, ref, visited);
          if (!arg0)
            return NULL_TREE;
        }
--- 2075,2082 ----
        for (i = 0; i < nargs; ++i)
        {
          arg1 = PHI_ARG_DEF (phi, i);
!         arg0 = get_continuation_for_phi_1 (phi, arg0, arg1, ref,
!                                            cnt, visited);
          if (!arg0)
            return NULL_TREE;
        }
*************** get_continuation_for_phi (gimple phi, ao
*** 2099,2109 ****
  
  void *
  walk_non_aliased_vuses (ao_ref *ref, tree vuse,
!                       void *(*walker)(ao_ref *, tree, void *),
                        void *(*translate)(ao_ref *, tree, void *), void *data)
  {
    bitmap visited = NULL;
    void *res;
  
    timevar_push (TV_ALIAS_STMT_WALK);
  
--- 2107,2118 ----
  
  void *
  walk_non_aliased_vuses (ao_ref *ref, tree vuse,
!                       void *(*walker)(ao_ref *, tree, unsigned int, void *),
                        void *(*translate)(ao_ref *, tree, void *), void *data)
  {
    bitmap visited = NULL;
    void *res;
+   unsigned int cnt = 0;
  
    timevar_push (TV_ALIAS_STMT_WALK);
  
*************** walk_non_aliased_vuses (ao_ref *ref, tre
*** 2112,2128 ****
        gimple def_stmt;
  
        /* ???  Do we want to account this to TV_ALIAS_STMT_WALK?  */
!       res = (*walker) (ref, vuse, data);
!       if (res)
        break;
  
        def_stmt = SSA_NAME_DEF_STMT (vuse);
        if (gimple_nop_p (def_stmt))
        break;
        else if (gimple_code (def_stmt) == GIMPLE_PHI)
!       vuse = get_continuation_for_phi (def_stmt, ref, &visited);
        else
        {
          if (stmt_may_clobber_ref_p_1 (def_stmt, ref))
            {
              if (!translate)
--- 2121,2145 ----
        gimple def_stmt;
  
        /* ???  Do we want to account this to TV_ALIAS_STMT_WALK?  */
!       res = (*walker) (ref, vuse, cnt, data);
!       /* Abort walk.  */
!       if (res == (void *)-1)
!       {
!         res = NULL;
!         break;
!       }
!       /* Lookup succeeded.  */
!       else if (res != NULL)
        break;
  
        def_stmt = SSA_NAME_DEF_STMT (vuse);
        if (gimple_nop_p (def_stmt))
        break;
        else if (gimple_code (def_stmt) == GIMPLE_PHI)
!       vuse = get_continuation_for_phi (def_stmt, ref, &cnt, &visited);
        else
        {
+         cnt++;
          if (stmt_may_clobber_ref_p_1 (def_stmt, ref))
            {
              if (!translate)
Index: gcc/tree-ssa-alias.h
===================================================================
*** gcc/tree-ssa-alias.h.orig   2012-08-21 16:46:21.000000000 +0200
--- gcc/tree-ssa-alias.h        2012-08-22 13:38:45.515016867 +0200
*************** extern bool stmt_may_clobber_ref_p (gimp
*** 107,115 ****
  extern bool stmt_may_clobber_ref_p_1 (gimple, ao_ref *);
  extern bool call_may_clobber_ref_p (gimple, tree);
  extern bool stmt_kills_ref_p (gimple, tree);
! extern tree get_continuation_for_phi (gimple, ao_ref *, bitmap *);
  extern void *walk_non_aliased_vuses (ao_ref *, tree,
!                                    void *(*)(ao_ref *, tree, void *),
                                     void *(*)(ao_ref *, tree, void *), void *);
  extern unsigned int walk_aliased_vdefs (ao_ref *, tree,
                                        bool (*)(ao_ref *, tree, void *),
--- 107,117 ----
  extern bool stmt_may_clobber_ref_p_1 (gimple, ao_ref *);
  extern bool call_may_clobber_ref_p (gimple, tree);
  extern bool stmt_kills_ref_p (gimple, tree);
! extern tree get_continuation_for_phi (gimple, ao_ref *,
!                                     unsigned int *, bitmap *);
  extern void *walk_non_aliased_vuses (ao_ref *, tree,
!                                    void *(*)(ao_ref *, tree,
!                                              unsigned int, void *),
                                     void *(*)(ao_ref *, tree, void *), void *);
  extern unsigned int walk_aliased_vdefs (ao_ref *, tree,
                                        bool (*)(ao_ref *, tree, void *),
Index: gcc/tree-ssa-pre.c
===================================================================
*** gcc/tree-ssa-pre.c.orig     2012-08-20 13:56:21.000000000 +0200
--- gcc/tree-ssa-pre.c  2012-08-22 13:38:45.516016867 +0200
*************** translate_vuse_through_block (VEC (vn_re
*** 1289,1297 ****
        if (use_oracle)
        {
          bitmap visited = NULL;
          /* Try to find a vuse that dominates this phi node by skipping
             non-clobbering statements.  */
!         vuse = get_continuation_for_phi (phi, &ref, &visited);
          if (visited)
            BITMAP_FREE (visited);
        }
--- 1289,1298 ----
        if (use_oracle)
        {
          bitmap visited = NULL;
+         unsigned int cnt;
          /* Try to find a vuse that dominates this phi node by skipping
             non-clobbering statements.  */
!         vuse = get_continuation_for_phi (phi, &ref, &cnt, &visited);
          if (visited)
            BITMAP_FREE (visited);
        }
Index: gcc/tree-ssa-sccvn.c
===================================================================
*** gcc/tree-ssa-sccvn.c.orig   2012-08-21 16:46:21.000000000 +0200
--- gcc/tree-ssa-sccvn.c        2012-08-22 13:40:03.232014176 +0200
*************** static vn_lookup_kind default_vn_walk_ki
*** 1330,1341 ****
     with the current VUSE and performs the expression lookup.  */
  
  static void *
! vn_reference_lookup_2 (ao_ref *op ATTRIBUTE_UNUSED, tree vuse, void *vr_)
  {
    vn_reference_t vr = (vn_reference_t)vr_;
    void **slot;
    hashval_t hash;
  
    if (last_vuse_ptr)
      *last_vuse_ptr = vuse;
  
--- 1330,1348 ----
     with the current VUSE and performs the expression lookup.  */
  
  static void *
! vn_reference_lookup_2 (ao_ref *op ATTRIBUTE_UNUSED, tree vuse,
!                      unsigned int cnt, void *vr_)
  {
    vn_reference_t vr = (vn_reference_t)vr_;
    void **slot;
    hashval_t hash;
  
+   /* This bounds the stmt walks we perform on reference lookups
+      to O(1) instead of O(N) where N is the number of dominating
+      stores.  */
+   if (cnt > (unsigned) PARAM_VALUE (PARAM_SCCVN_MAX_ALIAS_QUERIES_PER_ACCESS))
+     return (void *)-1;
+ 
    if (last_vuse_ptr)
      *last_vuse_ptr = vuse;
  
Index: gcc/params.def
===================================================================
*** gcc/params.def.orig 2012-08-21 16:46:21.000000000 +0200
--- gcc/params.def      2012-08-22 13:46:33.323000670 +0200
*************** DEFPARAM (PARAM_SCCVN_MAX_SCC_SIZE,
*** 752,757 ****
--- 752,768 ----
          "Maximum size of a SCC before SCCVN stops processing a function",
          10000, 10, 0)
  
+ /* The following is used as a stop-gap limit for cases where really huge
+    functions blow up compile-time use too much.  It limits the number of
+    alias-queries we do for finding common subexpressions for memory loads and
+    stores.  The number of alias-queries is otherwise limited by the number of
+    stores on paths to function entry.  */
+ 
+ DEFPARAM (PARAM_SCCVN_MAX_ALIAS_QUERIES_PER_ACCESS,
+         "sccvn-max-alias-queries-per-access",
+         "Maximum number of disambiguations to perform per memory access",
+         1000, 0, 0)
+ 
  DEFPARAM (PARAM_IRA_MAX_LOOPS_NUM,
          "ira-max-loops-num",
          "Max loops number for regional RA",
Index: gcc/doc/invoke.texi
===================================================================
*** gcc/doc/invoke.texi.orig    2012-08-17 09:49:37.000000000 +0200
--- gcc/doc/invoke.texi 2012-08-22 13:46:36.765000551 +0200
*************** processing.  If this limit is hit, SCCVN
*** 9221,9226 ****
--- 9221,9234 ----
  function is not done and optimizations depending on it are
  disabled.  The default maximum SCC size is 10000.
  
+ @item sccvn-max-alias-queries-per-access
+ Maximum number of alias-oracle queries we perform when looking for
+ redundancies for loads and stores.  If this limit is hit the search
+ is aborted and the load or store is not considered redundant.  The
+ number of queries is algorithmically limited to the number of
+ stores on all paths from the load to the function entry.
+ The default maxmimum number of queries is 1000.
+ 
  @item ira-max-loops-num
  IRA uses regional register allocation by default.  If a function
  contains more loops than the number given by this parameter, only at most

Reply via email to