[PATCH] Alternative solution for PR36343, missed call-clobbering due to TBAA pruning of points-to sets

Daniel Berlin dberlin@dberlin.org
Wed May 28 17:41:00 GMT 2008


This is fine by me.
You should be aware that trying to track which pointers point only to
non-local memory is, well, tricky.
I once replaced ANYTHING with NONLOCAL and made it compute the exact
set for ANYTHING, and this causes massive points-to set explosions
(see 4.2!)

You would really need to compute points-to with NONLOCAL being a dummy
variable (IE don't allow adds to NONLOCAL), then compute escaping,
then add all the escaped variables to NONLOCAL, transitive close
NONLOCAL (IE add *NONLOCAL to NONLOCAL until it stops changing) and
treat it specially in *_what_p_points_to.

Alternatively, you could compute interprocedural MOD/REF for all
functions using the points-to info, and it will give you exact sets.

I never got around to doing either, though i do have something along
the lines of the second path in a tree somewhere :)


On Wed, May 28, 2008 at 11:10 AM, Richard Guenther <rguenther@suse.de> wrote:
>
> This re-implements the call-clobbering code that uses the final
> TBAA-pruned points-to sets to use the original points-to solution.
> This fixes PR36343 (we may not use flow-insensitive TBAA-pruning
> to prune call clobber variables) and PR36347 (we drop to pt_anything
> for pointers that are not dereferenced but passed to calls - which
> causes a bunch of extra call clobbering).
>
> It does so by adding a new function clobber_what_p_points_to mirroring
> find_what_p_points_to (but of course suitable for the call clobber
> problem).
>
> It also fixes one nit in the TBAA-pruning code (we were only not pruning
> if the pointer was not dereferenced _and_ the pointed to pointer was
> not dereferenced).  It doesn't fix the ineffectiveness of TBAA-pruning
> though (PR36345).
>
> It also uses the fact that escaping pointers that only escape through
> pure/const calls or through the return statement do not need to add to
> the call clobbered variables.  Likewise it optimizes the case of
> escaped pt_anything parameters, where we know they cannot point to
> local memory.
>
> A similar version of the patch for the 4.3 branch exists to fix
> PR36343, as alternative to the (safer) version at
> http://gcc.gnu.org/ml/gcc-patches/2008-05/msg01709.html
>
> I have some followup patches for the trunk that get rid of most of
> the "interesting" parts of the call clobbering code like clobbering
> memory tags left and right just to collect enough to not break
> testcases (actually I believe the fix for PR36339 fixed all of this).
>
>
> I'm currently re-bootstrapping and testing this on
> x86_64-unknown-linux-gnu as I added the ESCAPE_TO_RETURN optimization
> late in the game.
>
>
> Ok for mainline if that passes?
>
> Thanks,
> Richard.
>
> 2008-05-27  Richard Guenther  <rguenther@suse.de>
>
>        PR tree-optimization/36343
>        PR tree-optimization/36346
>        PR tree-optimization/36347
>        * tree-flow.h (clobber_what_p_points_to): Declare.
>        * tree-ssa-structalias.c (set_uids_in_ptset): Whether the
>        pointed-to variable is dereferenced is irrelevant to whether
>        the pointer can access the pointed-to variable.
>        (clobber_what_p_points_to): New function.
>        * tree-ssa-alias.c (set_initial_properties): Use it.
>
>        * gcc.c-torture/execute/pr36343.c: New testcase.
>
> Index: gcc/tree-flow.h
> ===================================================================
> *** gcc/tree-flow.h.orig        2008-05-28 16:04:22.000000000 +0200
> --- gcc/tree-flow.h     2008-05-28 16:04:52.000000000 +0200
> *************** tree gimple_fold_indirect_ref (tree);
> *** 1167,1172 ****
> --- 1167,1173 ----
>
>  /* In tree-ssa-structalias.c */
>  bool find_what_p_points_to (tree);
> + bool clobber_what_p_points_to (tree);
>
>  /* In tree-ssa-live.c */
>  extern void remove_unused_locals (void);
> Index: gcc/tree-ssa-alias.c
> ===================================================================
> *** gcc/tree-ssa-alias.c.orig   2008-05-28 16:04:46.000000000 +0200
> --- gcc/tree-ssa-alias.c        2008-05-28 16:04:52.000000000 +0200
> *************** set_initial_properties (struct alias_inf
> *** 545,552 ****
>      {
>        struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
>        tree tag = symbol_mem_tag (SSA_NAME_VAR (ptr));
> !
> !       if (pi->value_escapes_p)
>        {
>          /* If PTR escapes then its associated memory tags and
>             pointed-to variables are call-clobbered.  */
> --- 545,555 ----
>      {
>        struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
>        tree tag = symbol_mem_tag (SSA_NAME_VAR (ptr));
> !
> !       /* A pointer that only escapes to a pure or const function or via
> !        a function return does not add to the call clobber solution.  */
> !       if (pi->value_escapes_p
> !         && pi->escape_mask & ~(ESCAPE_TO_PURE_CONST|ESCAPE_TO_RETURN))
>        {
>          /* If PTR escapes then its associated memory tags and
>             pointed-to variables are call-clobbered.  */
> *************** set_initial_properties (struct alias_inf
> *** 556,579 ****
>          if (tag)
>            mark_call_clobbered (tag, pi->escape_mask);
>
> !         if (pi->pt_vars)
> !           {
> !             bitmap_iterator bi;
> !             unsigned int j;
> !             EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, j, bi)
> !               {
> !                 tree alias = referenced_var (j);
> !
> !                 /* If you clobber one part of a structure, you
> !                    clobber the entire thing.  While this does not make
> !                    the world a particularly nice place, it is necessary
> !                    in order to allow C/C++ tricks that involve
> !                    pointer arithmetic to work.  */
> !                 if (!unmodifiable_var_p (alias))
> !                   mark_call_clobbered (alias, pi->escape_mask);
> !               }
> !           }
> !         else if (pi->pt_anything)
>            {
>              any_pt_anything = true;
>              pt_anything_mask |= pi->escape_mask;
> --- 559,571 ----
>          if (tag)
>            mark_call_clobbered (tag, pi->escape_mask);
>
> !         /* Defer to points-to analysis if possible, otherwise
> !            clobber all addressable variables.  Parameters cannot
> !            point to local memory though.
> !            ???  Properly tracking which pointers point to non-local
> !            memory only would make a big difference here.  */
> !         if (!clobber_what_p_points_to (ptr)
> !             && !(pi->escape_mask & ESCAPE_IS_PARM))
>            {
>              any_pt_anything = true;
>              pt_anything_mask |= pi->escape_mask;
> Index: gcc/testsuite/gcc.c-torture/execute/pr36343.c
> ===================================================================
> *** /dev/null   1970-01-01 00:00:00.000000000 +0000
> --- gcc/testsuite/gcc.c-torture/execute/pr36343.c       2008-05-28 16:04:52.000000000 +0200
> ***************
> *** 0 ****
> --- 1,32 ----
> + extern void abort (void);
> +
> + void __attribute__((noinline))
> + bar (int **p)
> + {
> +   float *q = (float *)p;
> +   *q = 0.0;
> + }
> +
> + float __attribute__((noinline))
> + foo (int b)
> + {
> +   int *i = 0;
> +   float f = 1.0;
> +   int **p;
> +   if (b)
> +     p = &i;
> +   else
> +     p = (int **)&f;
> +   bar (p);
> +   if (b)
> +     return **p;
> +   return f;
> + }
> +
> + int main()
> + {
> +   if (foo(0) != 0.0)
> +     abort ();
> +   return 0;
> + }
> +
> Index: gcc/tree-ssa-structalias.c
> ===================================================================
> *** gcc/tree-ssa-structalias.c.orig     2008-05-28 16:04:22.000000000 +0200
> --- gcc/tree-ssa-structalias.c  2008-05-28 16:12:39.000000000 +0200
> *************** set_uids_in_ptset (tree ptr, bitmap into
> *** 4664,4680 ****
>          || TREE_CODE (vi->decl) == RESULT_DECL)
>        {
>          /* Just add VI->DECL to the alias set.
> !            Don't type prune artificial vars.  */
> !         if (vi->is_artificial_var)
>            bitmap_set_bit (into, DECL_UID (vi->decl));
>          else
>            {
>              alias_set_type var_alias_set, ptr_alias_set;
>              var_alias_set = get_alias_set (vi->decl);
>              ptr_alias_set = get_alias_set (TREE_TYPE (TREE_TYPE (ptr)));
> !             if (no_tbaa_pruning
> !                 || (!is_derefed && !vi->directly_dereferenced)
> !                 || alias_sets_conflict_p (ptr_alias_set, var_alias_set))
>                bitmap_set_bit (into, DECL_UID (vi->decl));
>            }
>        }
> --- 4664,4682 ----
>          || TREE_CODE (vi->decl) == RESULT_DECL)
>        {
>          /* Just add VI->DECL to the alias set.
> !            Don't type prune artificial vars or points-to sets
> !            for pointers that have not been dereferenced or with
> !            type-based pruning disabled.  */
> !         if (vi->is_artificial_var
> !             || !is_derefed
> !             || no_tbaa_pruning)
>            bitmap_set_bit (into, DECL_UID (vi->decl));
>          else
>            {
>              alias_set_type var_alias_set, ptr_alias_set;
>              var_alias_set = get_alias_set (vi->decl);
>              ptr_alias_set = get_alias_set (TREE_TYPE (TREE_TYPE (ptr)));
> !             if (alias_sets_conflict_p (ptr_alias_set, var_alias_set))
>                bitmap_set_bit (into, DECL_UID (vi->decl));
>            }
>        }
> *************** find_what_p_points_to (tree p)
> *** 4885,4891 ****
> --- 4887,4957 ----
>    return false;
>  }
>
> + /* Mark everything that p points to as call clobbered.  Returns true
> +    if everything is done and false if all addressable variables need to
> +    be clobbered because p points to anything.  */
>
> + bool
> + clobber_what_p_points_to (tree p)
> + {
> +   tree lookup_p = p;
> +   varinfo_t vi;
> +   struct ptr_info_def *pi;
> +   unsigned int i;
> +   bitmap_iterator bi;
> +
> +   if (!have_alias_info)
> +     return false;
> +
> +   /* For parameters, get at the points-to set for the actual parm
> +      decl.  */
> +   if (TREE_CODE (p) == SSA_NAME
> +       && TREE_CODE (SSA_NAME_VAR (p)) == PARM_DECL
> +       && SSA_NAME_IS_DEFAULT_DEF (p))
> +     lookup_p = SSA_NAME_VAR (p);
> +
> +   vi = lookup_vi_for_tree (lookup_p);
> +   if (!vi)
> +     return false;
> +
> +   /* We are asking for the points-to solution of pointers.  */
> +   gcc_assert (!vi->is_artificial_var
> +             && vi->size == vi->fullsize);
> +
> +   pi = get_ptr_info (p);
> +
> +   /* This variable may have been collapsed, let's get the real
> +      variable.  */
> +   vi = get_varinfo (find (vi->id));
> +
> +   /* Mark variables in the solution call-clobbered.  */
> +   EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
> +     {
> +       varinfo_t vi = get_varinfo (i);
> +
> +       if (vi->is_artificial_var)
> +       {
> +         /* nothing_id and readonly_id do not cause any
> +            call clobber ops.  For anything_id and integer_id
> +            we need to clobber all addressable vars.  */
> +         if (vi->id == anything_id
> +             || vi->id == integer_id)
> +           return false;
> +       }
> +
> +       /* Only artificial heap-vars are further interesting.  */
> +       if (vi->is_artificial_var && !vi->is_heap_var)
> +       continue;
> +
> +       if ((TREE_CODE (vi->decl) == VAR_DECL
> +          || TREE_CODE (vi->decl) == PARM_DECL
> +          || TREE_CODE (vi->decl) == RESULT_DECL)
> +         && !unmodifiable_var_p (vi->decl))
> +       mark_call_clobbered (vi->decl, pi->escape_mask);
> +     }
> +
> +   return true;
> + }
>
>  /* Dump points-to information to OUTFILE.  */
>
> Index: gcc/tree-ssa.c
> ===================================================================
> *** gcc/tree-ssa.c.orig 2008-05-28 16:04:22.000000000 +0200
> --- gcc/tree-ssa.c      2008-05-28 16:04:52.000000000 +0200
> *************** verify_flow_sensitive_alias_info (void)
> *** 571,577 ****
>          goto err;
>        }
>
> !       if (pi->value_escapes_p && pi->name_mem_tag)
>        {
>          tree t = memory_partition (pi->name_mem_tag);
>          if (t == NULL_TREE)
> --- 571,579 ----
>          goto err;
>        }
>
> !       if (pi->value_escapes_p
> !         && pi->escape_mask & ~(ESCAPE_TO_PURE_CONST|ESCAPE_TO_RETURN)
> !         && pi->name_mem_tag)
>        {
>          tree t = memory_partition (pi->name_mem_tag);
>          if (t == NULL_TREE)
>



More information about the Gcc-patches mailing list