[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