The following patch addresses PR67170 which shows we fail to disambiguate
INTENT(IN) variables against for example recursive calls.  The trick
in solving this is to notice that when a function has a fn spec
attribute that says memory reachable by a parameter is not modified
then that memory behaves as if it were readonly throughout the function
and thus it doesn't have a dependence on any other reference in that
function.

In the PR I prototyped a patch in the alias oracle itself but that's
too expensive (we need to find the index of a PARM_DECL).  Thus the
following patch implements that trick in the value-numbering machinery
instead.  Going with the alias oracle patch would still be possible
if we decide on caching the fn spec information in a place that is
O(1) accessible from relevant memory references (thus either on the
SSA default def or the PARM_DECL itself).

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

This improves a future important benchmark implementing a
Sudoku puzzle solver considerably (~10% on x86_64 IIRC).

Richard.

2015-09-29  Richard Biener  <rguent...@suse.de>

        PR tree-optimization/67170
        * tree-ssa-alias.h (get_continuation_for_phi): Adjust
        the translate function pointer parameter to get the
        bool whether to disambiguate only by reference.
        (walk_non_aliased_vuses): Likewise.
        * tree-ssa-alias.c (maybe_skip_until): Adjust.
        (get_continuation_for_phi_1): Likewise.
        (get_continuation_for_phi): Likewise.
        (walk_non_aliased_vuses): Likewise.
        * tree-ssa-sccvn.c (const_parms): New bitmap.
        (vn_reference_lookup_3): Adjust for interface change.
        Disambiguate parameters pointing to readonly memory.
        (free_scc_vn): Free const_parms.
        (run_scc_vn): Initialize const_parms from a fn spec attribute.

        * gfortran.dg/pr67170.f90: New testcase.

Index: gcc/tree-ssa-alias.c
===================================================================
*** gcc/tree-ssa-alias.c        (revision 228230)
--- gcc/tree-ssa-alias.c        (working copy)
*************** static bool
*** 2442,2448 ****
  maybe_skip_until (gimple *phi, tree target, ao_ref *ref,
                  tree vuse, unsigned int *cnt, bitmap *visited,
                  bool abort_on_visited,
!                 void *(*translate)(ao_ref *, tree, void *, bool),
                  void *data)
  {
    basic_block bb = gimple_bb (phi);
--- 2442,2448 ----
  maybe_skip_until (gimple *phi, tree target, ao_ref *ref,
                  tree vuse, unsigned int *cnt, bitmap *visited,
                  bool abort_on_visited,
!                 void *(*translate)(ao_ref *, tree, void *, bool *),
                  void *data)
  {
    basic_block bb = gimple_bb (phi);
*************** maybe_skip_until (gimple *phi, tree targ
*** 2477,2484 ****
          ++*cnt;
          if (stmt_may_clobber_ref_p_1 (def_stmt, ref))
            {
              if (translate
!                 && (*translate) (ref, vuse, data, true) == NULL)
                ;
              else
                return false;
--- 2477,2485 ----
          ++*cnt;
          if (stmt_may_clobber_ref_p_1 (def_stmt, ref))
            {
+             bool disambiguate_only = true;
              if (translate
!                 && (*translate) (ref, vuse, data, &disambiguate_only) == NULL)
                ;
              else
                return false;
*************** static tree
*** 2505,2511 ****
  get_continuation_for_phi_1 (gimple *phi, tree arg0, tree arg1,
                            ao_ref *ref, unsigned int *cnt,
                            bitmap *visited, bool abort_on_visited,
!                           void *(*translate)(ao_ref *, tree, void *, bool),
                            void *data)
  {
    gimple *def0 = SSA_NAME_DEF_STMT (arg0);
--- 2506,2512 ----
  get_continuation_for_phi_1 (gimple *phi, tree arg0, tree arg1,
                            ao_ref *ref, unsigned int *cnt,
                            bitmap *visited, bool abort_on_visited,
!                           void *(*translate)(ao_ref *, tree, void *, bool *),
                            void *data)
  {
    gimple *def0 = SSA_NAME_DEF_STMT (arg0);
*************** get_continuation_for_phi_1 (gimple *phi,
*** 2547,2559 ****
    else if ((common_vuse = gimple_vuse (def0))
           && common_vuse == gimple_vuse (def1))
      {
        *cnt += 2;
        if ((!stmt_may_clobber_ref_p_1 (def0, ref)
           || (translate
!              && (*translate) (ref, arg0, data, true) == NULL))
          && (!stmt_may_clobber_ref_p_1 (def1, ref)
              || (translate
!                 && (*translate) (ref, arg1, data, true) == NULL)))
        return common_vuse;
      }
  
--- 2548,2561 ----
    else if ((common_vuse = gimple_vuse (def0))
           && common_vuse == gimple_vuse (def1))
      {
+       bool disambiguate_only = true;
        *cnt += 2;
        if ((!stmt_may_clobber_ref_p_1 (def0, ref)
           || (translate
!              && (*translate) (ref, arg0, data, &disambiguate_only) == NULL))
          && (!stmt_may_clobber_ref_p_1 (def1, ref)
              || (translate
!                 && (*translate) (ref, arg1, data, &disambiguate_only) == 
NULL)))
        return common_vuse;
      }
  
*************** tree
*** 2571,2577 ****
  get_continuation_for_phi (gimple *phi, ao_ref *ref,
                          unsigned int *cnt, bitmap *visited,
                          bool abort_on_visited,
!                         void *(*translate)(ao_ref *, tree, void *, bool),
                          void *data)
  {
    unsigned nargs = gimple_phi_num_args (phi);
--- 2573,2579 ----
  get_continuation_for_phi (gimple *phi, ao_ref *ref,
                          unsigned int *cnt, bitmap *visited,
                          bool abort_on_visited,
!                         void *(*translate)(ao_ref *, tree, void *, bool *),
                          void *data)
  {
    unsigned nargs = gimple_phi_num_args (phi);
*************** get_continuation_for_phi (gimple *phi, a
*** 2648,2654 ****
  void *
  walk_non_aliased_vuses (ao_ref *ref, tree vuse,
                        void *(*walker)(ao_ref *, tree, unsigned int, void *),
!                       void *(*translate)(ao_ref *, tree, void *, bool),
                        tree (*valueize)(tree),
                        void *data)
  {
--- 2650,2656 ----
  void *
  walk_non_aliased_vuses (ao_ref *ref, tree vuse,
                        void *(*walker)(ao_ref *, tree, unsigned int, void *),
!                       void *(*translate)(ao_ref *, tree, void *, bool *),
                        tree (*valueize)(tree),
                        void *data)
  {
*************** walk_non_aliased_vuses (ao_ref *ref, tre
*** 2690,2696 ****
            {
              if (!translate)
                break;
!             res = (*translate) (ref, vuse, data, false);
              /* Failed lookup and translation.  */
              if (res == (void *)-1)
                {
--- 2692,2699 ----
            {
              if (!translate)
                break;
!             bool disambiguate_only = false;
!             res = (*translate) (ref, vuse, data, &disambiguate_only);
              /* Failed lookup and translation.  */
              if (res == (void *)-1)
                {
*************** walk_non_aliased_vuses (ao_ref *ref, tre
*** 2701,2707 ****
              else if (res != NULL)
                break;
              /* Translation succeeded, continue walking.  */
!             translated = true;
            }
          vuse = gimple_vuse (def_stmt);
        }
--- 2704,2710 ----
              else if (res != NULL)
                break;
              /* Translation succeeded, continue walking.  */
!             translated = translated || !disambiguate_only;
            }
          vuse = gimple_vuse (def_stmt);
        }
Index: gcc/tree-ssa-alias.h
===================================================================
*** gcc/tree-ssa-alias.h        (revision 228230)
--- gcc/tree-ssa-alias.h        (working copy)
*************** extern bool stmt_kills_ref_p (gimple *,
*** 118,129 ****
  extern bool stmt_kills_ref_p (gimple *, ao_ref *);
  extern tree get_continuation_for_phi (gimple *, ao_ref *,
                                      unsigned int *, bitmap *, bool,
!                                     void *(*)(ao_ref *, tree, void *, bool),
                                      void *);
  extern void *walk_non_aliased_vuses (ao_ref *, tree,
                                     void *(*)(ao_ref *, tree,
                                               unsigned int, void *),
!                                    void *(*)(ao_ref *, tree, void *, bool),
                                     tree (*)(tree),
                                     void *);
  extern unsigned int walk_aliased_vdefs (ao_ref *, tree,
--- 118,129 ----
  extern bool stmt_kills_ref_p (gimple *, ao_ref *);
  extern tree get_continuation_for_phi (gimple *, ao_ref *,
                                      unsigned int *, bitmap *, bool,
!                                     void *(*)(ao_ref *, tree, void *, bool *),
                                      void *);
  extern void *walk_non_aliased_vuses (ao_ref *, tree,
                                     void *(*)(ao_ref *, tree,
                                               unsigned int, void *),
!                                    void *(*)(ao_ref *, tree, void *, bool *),
                                     tree (*)(tree),
                                     void *);
  extern unsigned int walk_aliased_vdefs (ao_ref *, tree,
Index: gcc/tree-ssa-sccvn.c
===================================================================
*** gcc/tree-ssa-sccvn.c        (revision 228230)
--- gcc/tree-ssa-sccvn.c        (working copy)
*************** along with GCC; see the file COPYING3.
*** 120,125 ****
--- 120,126 ----
  static tree *last_vuse_ptr;
  static vn_lookup_kind vn_walk_kind;
  static vn_lookup_kind default_vn_walk_kind;
+ bitmap const_parms;
  
  /* vn_nary_op hashtable helpers.  */
  
*************** vn_reference_lookup_or_insert_for_pieces
*** 1656,1676 ****
  /* Callback for walk_non_aliased_vuses.  Tries to perform a lookup
     from the statement defining VUSE and if not successful tries to
     translate *REFP and VR_ through an aggregate copy at the definition
!    of VUSE.  */
  
  static void *
  vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_,
!                      bool disambiguate_only)
  {
    vn_reference_t vr = (vn_reference_t)vr_;
    gimple *def_stmt = SSA_NAME_DEF_STMT (vuse);
!   tree base;
    HOST_WIDE_INT offset, maxsize;
    static vec<vn_reference_op_s>
      lhs_ops = vNULL;
    ao_ref lhs_ref;
    bool lhs_ref_ok = false;
  
    /* First try to disambiguate after value-replacing in the definitions LHS.  
*/
    if (is_gimple_assign (def_stmt))
      {
--- 1657,1691 ----
  /* Callback for walk_non_aliased_vuses.  Tries to perform a lookup
     from the statement defining VUSE and if not successful tries to
     translate *REFP and VR_ through an aggregate copy at the definition
!    of VUSE.  If *DISAMBIGUATE_ONLY is true then do not perform translation
!    of *REF and *VR.  If only disambiguation was performed then
!    *DISAMBIGUATE_ONLY is set to true.  */
  
  static void *
  vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_,
!                      bool *disambiguate_only)
  {
    vn_reference_t vr = (vn_reference_t)vr_;
    gimple *def_stmt = SSA_NAME_DEF_STMT (vuse);
!   tree base = ao_ref_base (ref);
    HOST_WIDE_INT offset, maxsize;
    static vec<vn_reference_op_s>
      lhs_ops = vNULL;
    ao_ref lhs_ref;
    bool lhs_ref_ok = false;
  
+   /* If the reference is based on a parameter that was determined as
+      pointing to readonly memory it doesn't change.  */
+   if (TREE_CODE (base) == MEM_REF
+       && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME
+       && SSA_NAME_IS_DEFAULT_DEF (TREE_OPERAND (base, 0))
+       && bitmap_bit_p (const_parms,
+                      SSA_NAME_VERSION (TREE_OPERAND (base, 0))))
+     {
+       *disambiguate_only = true;
+       return NULL;
+     }
+ 
    /* First try to disambiguate after value-replacing in the definitions LHS.  
*/
    if (is_gimple_assign (def_stmt))
      {
*************** vn_reference_lookup_3 (ao_ref *ref, tree
*** 1687,1693 ****
                                                      TREE_TYPE (lhs), lhs_ops);
          if (lhs_ref_ok
              && !refs_may_alias_p_1 (ref, &lhs_ref, true))
!           return NULL;
        }
        else
        {
--- 1702,1711 ----
                                                      TREE_TYPE (lhs), lhs_ops);
          if (lhs_ref_ok
              && !refs_may_alias_p_1 (ref, &lhs_ref, true))
!           {
!             *disambiguate_only = true;
!             return NULL;
!           }
        }
        else
        {
*************** vn_reference_lookup_3 (ao_ref *ref, tree
*** 1723,1736 ****
          for (unsigned i = 0; i < gimple_call_num_args (def_stmt); ++i)
            gimple_call_set_arg (def_stmt, i, oldargs[i]);
          if (!res)
!           return NULL;
        }
      }
  
!   if (disambiguate_only)
      return (void *)-1;
  
-   base = ao_ref_base (ref);
    offset = ref->offset;
    maxsize = ref->max_size;
  
--- 1741,1756 ----
          for (unsigned i = 0; i < gimple_call_num_args (def_stmt); ++i)
            gimple_call_set_arg (def_stmt, i, oldargs[i]);
          if (!res)
!           {
!             *disambiguate_only = true;
!             return NULL;
!           }
        }
      }
  
!   if (*disambiguate_only)
      return (void *)-1;
  
    offset = ref->offset;
    maxsize = ref->max_size;
  
*************** free_scc_vn (void)
*** 4342,4347 ****
--- 4362,4369 ----
    XDELETE (valid_info);
    free_vn_table (optimistic_info);
    XDELETE (optimistic_info);
+ 
+   BITMAP_FREE (const_parms);
  }
  
  /* Set *ID according to RESULT.  */
*************** run_scc_vn (vn_lookup_kind default_vn_wa
*** 4677,4682 ****
--- 4699,4727 ----
  
    init_scc_vn ();
  
+   /* Collect pointers we know point to readonly memory.  */
+   const_parms = BITMAP_ALLOC (NULL);
+   tree fnspec = lookup_attribute ("fn spec",
+                                 TYPE_ATTRIBUTES (TREE_TYPE (cfun->decl)));
+   if (fnspec)
+     {
+       fnspec = TREE_VALUE (TREE_VALUE (fnspec));
+       i = 1;
+       for (tree arg = DECL_ARGUMENTS (cfun->decl);
+          arg; arg = DECL_CHAIN (arg), ++i)
+       {
+         if (i >= (unsigned) TREE_STRING_LENGTH (fnspec))
+           break;
+         if (TREE_STRING_POINTER (fnspec)[i]  == 'R'
+             || TREE_STRING_POINTER (fnspec)[i] == 'r')
+           {
+             tree name = ssa_default_def (cfun, arg);
+             if (name)
+               bitmap_set_bit (const_parms, SSA_NAME_VERSION (name));
+           }
+       }
+     }
+ 
    /* Mark all edges as possibly executable.  */
    FOR_ALL_BB_FN (bb, cfun)
      {
Index: gcc/testsuite/gfortran.dg/pr67170.f90
===================================================================
*** gcc/testsuite/gfortran.dg/pr67170.f90       (revision 0)
--- gcc/testsuite/gfortran.dg/pr67170.f90       (revision 0)
***************
*** 0 ****
--- 1,31 ----
+ ! { dg-do compile }
+ ! { dg-options "-O -fdump-tree-fre1" }
+ 
+ module test_module
+   integer, parameter :: r=10
+    integer :: data(r, r), block(r, r, r)
+   contains
+ recursive subroutine foo(arg) 
+ integer, intent(in) :: arg
+ integer :: loop, x(r), y(r)
+ 
+    where(data(arg, :) /= 0)
+       x = data(arg, :)
+        y = l
+    elsewhere
+       x = 1
+       y = r
+    end where
+ 
+ do loop = x(1), y(1)
+    if(block(arg, 1, loop) <= 0) cycle
+    block(arg, 1:4, loop) =  block(arg, 1:4, i1) + 1
+    call foo(arg + 2)     
+    block(arg, 1:4, loop) = block(arg, 1:4, i1) + 10
+ end do
+ end subroutine foo
+ 
+ end module test_module
+ end program
+ 
+ ! { dg-final { scan-tree-dump-times "= \\*arg_\[0-9\]+\\(D\\);" 1 "fre1" } }

Reply via email to