[tree-ssa]: Fix small points-to bug
Daniel Berlin
dberlin@dberlin.org
Sun Dec 28 07:05:00 GMT 2003
For some reason, i thought we made the GIMPLE grammar only have
single-level component accesses, not multi-level component accesses.
Apparently, i was wrong.
This fixes the x86 bootstrap failure.
I also removed some unused code, and added a new function we'll be
using to help trim the "may point to global memory" flag on variables.
Bootstrapped and regtests on i686-pc-linux-gnu and powerpc-darwin.
2003-12-27 Daniel Berlin <dberlin@dberlin.org>
* Makefile.in (tree-alias-ander.o): Add cgraph.h dependency.
(tree-alias-common.o): Ditto.
* tree-alias-ander.c: Remove hashtab.h, include cgraph.h
(andersen_empty_points_to_set): New function.
(andersen_ops): Add empty_points_to_set function.
(get_ptset): New helper function.
(pta_get_ptsize): Remove.
(andersen_cleanup): Always delete the splay tree.
(andersen_function_call): Use cgraph info.
(andersen_same_points_to_set): Use get_ptset.
* tree-alias-common.c: Remove splay-tree.h include.
Include cgraph.h.
(annot_hash): Remove.
(annot_eq): Remove.
(struct alias_annot_entry): Remove.
(alias_annot): Remove.
(get_alias_var_decl): Remove calls to lookup/insert into alias_annot.
(create_alias_var): Ditto.
(delete_alias_var): Ditto.
(same_points_to_set): Ditto.
(ptr_may_alias_var): Ditto.
(get_alias_var): Work a little on field-based stuff.
(deal_with_call_aliasing): Look into return exprs that contain
MODIFY_EXPR's.
(init_alias_vars): Don't create alias_annot.
(empty_points_to_set): New function.
(find_func_aliases): Handle COMPONENT_REF of COMPONENT_REF
properly.
(create_fun_alias_var): Use cgraph info.
* tree-alias-common.h (struct tree_alias_ops): add
empty_points_to_set function.
(empty_points_to_set): New function prototype.
Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.903.2.158
diff -u -3 -p -r1.903.2.158 Makefile.in
--- Makefile.in 17 Dec 2003 19:53:00 -0000 1.903.2.158
+++ Makefile.in 28 Dec 2003 00:52:13 -0000
@@ -1544,10 +1544,10 @@ tree-alias-type.o: tree-alias-type.c tre
$(GGC_H) $(TM_H) coretypes.h $(VARRAY_H)
tree-alias-ander.o: tree-alias-ander.c tree-alias-ander.h $(SYSTEM_H) \
$(CONFIG_H) $(GGC_H) $(TREE_H) $(TREE_FLOW_H) tree-alias-common.h \
- $(TM_H) coretypes.h
+ $(TM_H) coretypes.h cgraph.h
tree-alias-common.o: tree-alias-common.c tree-alias-common.h
$(SYSTEM_H) \
$(CONFIG_H) $(GGC_H) $(TREE_H) gt-tree-alias-common.h
$(TREE_FLOW_H) \
- $(TM_H) coretypes.h
+ $(TM_H) coretypes.h cgraph.h
tree-ssa.o : tree-ssa.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
$(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h
diagnostic.h \
errors.h toplev.h function.h $(TIMEVAR_H) tree-alias-common.h \
Index: tree-alias-ander.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-alias-ander.c,v
retrieving revision 1.1.2.22
diff -u -3 -p -r1.1.2.22 tree-alias-ander.c
--- tree-alias-ander.c 8 Dec 2003 22:24:01 -0000 1.1.2.22
+++ tree-alias-ander.c 28 Dec 2003 00:52:13 -0000
@@ -42,11 +42,11 @@ Foundation, Inc., 59 Temple Place, Suite
#include "tree-inline.h"
#include "varray.h"
#include "tree-simple.h"
-#include "hashtab.h"
#include "splay-tree.h"
#include "engine/util.h"
#include "libcompat/regions.h"
#include "andersen_terms.h"
+#include "cgraph.h"
/* Andersen's interprocedural points-to analysis.
This is a flow-insensitive, context insensitive algorithm.
@@ -80,7 +80,7 @@ Foundation, Inc., 59 Temple Place, Suite
beyond the scope of this documentation. See the libbanshee
documentation, and references therein for more enlightenment.
- That said, our constraints inclusion constraints of set
+ That said, our constraints inclusion constraints of set
expressions. Given the helper functions, the various inference
functions we implement should *look* relatively straightforward.
@@ -117,13 +117,15 @@ static int print_out_result (splay_tree_
static void andersen_cleanup (struct tree_alias_ops *);
static bool andersen_may_alias (struct tree_alias_ops *, alias_typevar,
alias_typevar);
-static bool andersen_same_points_to_set (struct tree_alias_ops *,
alias_typevar,
- alias_typevar);
+static bool andersen_same_points_to_set (struct tree_alias_ops *,
+ alias_typevar, alias_typevar);
+static bool andersen_empty_points_to_set (struct tree_alias_ops *,
+ alias_typevar);
static alias_typevar andersen_add_var (struct tree_alias_ops *, tree);
static alias_typevar andersen_add_var_same (struct tree_alias_ops *,
tree, alias_typevar);
static bool pointer_destroying_op (tree);
-
+static aterm_list get_ptset (alias_typevar);
static splay_tree ptamap;
@@ -142,6 +144,7 @@ static struct tree_alias_ops andersen_op
andersen_function_call,
andersen_may_alias,
andersen_same_points_to_set,
+ andersen_empty_points_to_set,
0, /* data */
0, /* Currently non-interprocedural */
1 /* Can do IP on all statics without help. */
@@ -168,9 +171,6 @@ typedef aterm contents_type;
static contents_type pta_get_contents (aterm);
static void pr_ptset_aterm_elem (aterm);
static void pta_pr_ptset (contents_type);
-#if 0
-static int pta_get_ptsize (contents_type);
-#endif
/* Hook for debugging. This function is called instead of
aterm_inclusion, and lets us print the actual constraints as they
@@ -431,15 +431,6 @@ pta_pr_ptset (contents_type t)
deleteregion (scratch_rgn);
}
-#if 0
-static int
-pta_get_ptsize (contents_type t)
-{
- aterm_list ptset = aterm_tlb (t);
- return aterm_list_length (ptset);
-}
-#endif
-
/* Initialize Andersen alias analysis. */
static int initted = 0;
@@ -455,7 +446,7 @@ andersen_init (struct tree_alias_ops *op
dump_file = dump_begin (TDI_pta, &dump_flags);
ptamap = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
- /* Don't claim we can do ip partial unless the user requests it. */
+ /* Don't claim we can do ip partial unless we have unit_at_a_time
on. */
if (!flag_unit_at_a_time)
andersen_ops.ip_partial = 0;
@@ -487,11 +478,10 @@ andersen_cleanup (struct tree_alias_ops
splay_tree_foreach (ptamap, print_out_result, NULL);
dump_end (TDI_pta, dump_file);
}
-
+ splay_tree_delete (ptamap);
if (!flag_unit_at_a_time)
{
pta_reset ();
- splay_tree_delete (ptamap);
deleteregion (andersen_rgn);
andersen_rgn = NULL;
}
@@ -818,7 +808,7 @@ andersen_function_call (struct tree_alia
if (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_PTA_TYPEVAR (decl)
&& flag_unit_at_a_time
- && (!TREE_PUBLIC (decl) && TREE_STATIC (decl)))
+ && (cgraph_local_info (decl)->local))
{
return 0;
}
@@ -835,10 +825,22 @@ simple_cmp (const aterm a, const aterm b
}
-/* Determine if two aterm's have the same points-to set.
- When we didn't create global_var, we can just get the two points-to
- sets and compare the lengths, then the names.
- When we did create global_var, we have to filter it out. */
+/* Get the points-to set for TV, caching if it we had to compute it. */
+
+static aterm_list
+get_ptset (alias_typevar tv)
+{
+ aterm_list ptset;
+ ptset = ALIAS_TVAR_PTSET (tv);
+ if (ptset != NULL)
+ return ptset;
+ ptset = aterm_tlb (pta_get_contents (ALIAS_TVAR_ATERM (tv)));
+ ALIAS_TVAR_PTSET (tv) = ptset;
+ return ptset;
+}
+
+
+/* Determine if two aterm's have the same points-to set. */
static bool
andersen_same_points_to_set (struct tree_alias_ops *ops
ATTRIBUTE_UNUSED,
@@ -849,20 +851,8 @@ andersen_same_points_to_set (struct tree
aterm data1, data2;
region scratch_rgn = newregion ();
- ptset1 = ALIAS_TVAR_PTSET (ptrtv);
- ptset2 = ALIAS_TVAR_PTSET (vartv);
- /* Solve the points-to constraints and get the resulting sets if
- they weren't cached previously. */
- if (!ptset1)
- {
- ptset1 = aterm_tlb (pta_get_contents (ALIAS_TVAR_ATERM (ptrtv)));
- ALIAS_TVAR_PTSET (ptrtv) = ptset1;
- }
- if (!ptset2)
- {
- ptset2 = aterm_tlb (pta_get_contents (ALIAS_TVAR_ATERM (vartv)));
- ALIAS_TVAR_PTSET (vartv) = ptset2;
- }
+ ptset1 = get_ptset (ptrtv);
+ ptset2 = get_ptset (vartv);
if (aterm_list_length (ptset1) != aterm_list_length (ptset2))
{
@@ -912,18 +902,22 @@ andersen_may_alias (struct tree_alias_op
alias_typevar ptrtv, alias_typevar vartv)
{
aterm_list ptset;
- ptset = ALIAS_TVAR_PTSET (ptrtv);
-
- /* Solve the points-to constraints and get the resulting set if we
- haven't cached it. */
- if (!ptset)
- {
- ptset = aterm_tlb (pta_get_contents (ALIAS_TVAR_ATERM (ptrtv)));
- ALIAS_TVAR_PTSET (ptrtv) = ptset;
- }
+ ptset = get_ptset (ptrtv);
if (aterm_list_empty (ptset))
return false;
return aterm_list_member (ptset, ALIAS_TVAR_ATERM (vartv));
+}
+
+/* Determine whether PTRTV has an empty points-to set. IE it may not
+ point to anything. */
+
+static bool
+andersen_empty_points_to_set (struct tree_alias_ops *ops
ATTRIBUTE_UNUSED,
+ alias_typevar ptrtv)
+{
+ aterm_list ptset;
+ ptset = get_ptset (ptrtv);
+ return aterm_list_empty (ptset);
}
Index: tree-alias-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-alias-common.c,v
retrieving revision 1.1.2.45
diff -u -3 -p -r1.1.2.45 tree-alias-common.c
--- tree-alias-common.c 22 Dec 2003 22:50:16 -0000 1.1.2.45
+++ tree-alias-common.c 28 Dec 2003 00:52:13 -0000
@@ -47,8 +47,8 @@ Foundation, Inc., 59 Temple Place, Suite
#include "c-tree.h"
#include "tree-simple.h"
#include "hashtab.h"
-#include "splay-tree.h"
#include "function.h"
+#include "cgraph.h"
/* This file contains the implementation of the common parts of the
tree points-to analysis infrastructure.
@@ -90,8 +90,6 @@ static alias_typevar create_fun_alias_va
static alias_typevar create_fun_alias_var (tree, int);
static alias_typevar create_alias_var (tree);
static void intra_function_call (varray_type);
-static hashval_t annot_hash (const PTR);
-static int annot_eq (const PTR, const PTR);
static void get_values_from_constructor (tree, varray_type *);
static bool call_may_clobber (tree);
static bool call_may_return (tree);
@@ -128,44 +126,6 @@ call_may_return (tree expr)
return ! (flags & ECF_NORETURN);
}
-
-
-/* Alias annotation hash table entry.
- Used in the annotation hash table to map trees to their
- alias_typevar's. */
-
-struct alias_annot_entry GTY(())
-{
- tree key;
- alias_typevar value;
-};
-
-/* Alias annotation equality function. PENTRY is the hash table
- entry, PDATA is the entry we gave the function calling this.
- Return 1 if PENTRY is equal to PDATA. */
-
-static int
-annot_eq (const PTR pentry, const PTR pdata)
-{
- struct alias_annot_entry *entry = (struct alias_annot_entry *)pentry;
- struct alias_annot_entry *data = (struct alias_annot_entry *)pdata;
-
- return entry->key == data->key;
-}
-
-/* Alias annotation hash function. Hash PENTRY and return a value.
*/
-
-static hashval_t
-annot_hash (const PTR pentry)
-{
- struct alias_annot_entry *entry = (struct alias_annot_entry *)
pentry;
- return htab_hash_pointer (entry->key);
-}
-
-/* Alias annotation hash table. Maps vars to alias_typevars. */
-
-static GTY ((param_is (struct alias_annot_entry))) htab_t alias_annot;
-
/* Get the alias_typevar for DECL.
Creates the alias_typevar if it does not exist already. Also
handles FUNCTION_DECL properly. */
@@ -224,10 +184,6 @@ get_alias_var_decl (tree decl)
static alias_typevar
get_alias_var (tree expr)
{
- alias_typevar tvar;
- struct alias_annot_entry entry;
- struct alias_annot_entry *result;
-
/* If it's a decl, get the alias var of the decl. We farm this off
to get_alias_var_decl so it can abort if the alias var doesn't
exist, and in case something else *knows* it has a decl, and
@@ -236,20 +192,6 @@ get_alias_var (tree expr)
if (DECL_P (expr))
return get_alias_var_decl (expr);
- /* Non-DECL's alias vars must be temporary alias vars for an
- expression, since we never create non-temporary ones on anything
- but DECL's.
- Since they are temporary, we want to erase it from the annotation
- since they are use once. */
- entry.key = expr;
- result = htab_find (alias_annot, &entry);
- if (result != NULL && result->value != 0)
- {
- tvar = result->value;
- htab_remove_elt (alias_annot, &entry);
- return tvar;
- }
-
/* True constants have no aliases (unless modifiable strings are on,
in which case i don't think we'll end up with a STRING_CST
anyway) */
if (TREE_CODE_CLASS (TREE_CODE (expr)) == 'c')
@@ -272,7 +214,29 @@ get_alias_var (tree expr)
case COMPONENT_REF:
{
#if FIELD_BASED
- return get_alias_var (TREE_OPERAND (expr, 1));
+ bool safe = true;
+ tree p;
+ for (p = expr;
+ TREE_CODE (p) == COMPONENT_REF || TREE_CODE (p) == INDIRECT_REF;
+ p = TREE_OPERAND (p, 0))
+ {
+ if (TREE_CODE (TREE_TYPE (p)) == UNION_TYPE
+ || TREE_CODE (TREE_TYPE (p)) == QUAL_UNION_TYPE)
+ {
+ safe = false;
+ break;
+ }
+ }
+ if (!safe)
+ {
+ for (p = expr; TREE_CODE (p) == COMPONENT_REF;
+ p = TREE_OPERAND (p, 0));
+ return get_alias_var (p);
+ }
+ else
+ {
+ return get_alias_var (TREE_OPERAND (expr, 1));
+ }
#else
/* Find the first non-component ref, and return its alias
variable. */
tree p;
@@ -438,6 +402,13 @@ deal_with_call_aliasing (tree callargs,
static void
find_func_aliases (tree stp)
{
+ if (TREE_CODE (stp) == RETURN_EXPR)
+ {
+ stp = TREE_OPERAND (stp, 0);
+ if (!stp)
+ return;
+ }
+
if (TREE_CODE (stp) == MODIFY_EXPR
|| (DECL_P (stp) && DECL_INITIAL (stp) != NULL_TREE ))
{
@@ -461,7 +432,14 @@ find_func_aliases (tree stp)
return;
/* rhsAV might not have one, c.f. c = 5 */
rhsAV = get_alias_var (op1);
-
+#if !FIELD_BASED
+ while (TREE_CODE (op1) == COMPONENT_REF
+ && TREE_CODE (TREE_OPERAND (op1, 0)) == COMPONENT_REF)
+ {
+ op1 = TREE_OPERAND (op1, 0);
+ }
+#endif
+
/* You would think we could test rhsAV at the top, rather than
50 separate times, but we can't, because it can be NULL for
operator assignments, where we'd still collect the individual
@@ -548,7 +526,7 @@ find_func_aliases (tree stp)
get_alias_var (callop0),
args, addrargs))
{
- if (call_may_clobber (op1)
+ if (call_may_clobber (op1)
&& !current_alias_ops->ip
&& flag_argument_noalias != 2)
{
@@ -720,8 +698,7 @@ find_func_aliases (tree stp)
/* NORETURN and CONST functions have no effect on aliasing. */
if (call_may_clobber (stp))
if (current_alias_ops->function_call (current_alias_ops, NULL,
- callvar,
- args, addrargs))
+ callvar, args, addrargs))
if (!current_alias_ops->ip && flag_argument_noalias != 2)
intra_function_call (args);
}
@@ -766,8 +743,7 @@ create_fun_alias_var (tree decl, int for
&& !current_alias_ops->ip
/* FIXME: Need to let analyzer decide in partial case. */
&& (!current_alias_ops->ip_partial
- || !TREE_STATIC (decl)
- || TREE_PUBLIC (decl)))
+ || !cgraph_local_info (decl)->local))
current_alias_ops->simple_assign (current_alias_ops, tvar,
get_alias_var (pta_global_var));
}
@@ -906,19 +882,16 @@ create_fun_alias_var_ptf (tree decl, tre
static alias_typevar
create_alias_var (tree decl)
{
- struct alias_annot_entry entry, *result, *newentry, **slot;
-
alias_typevar avar;
+
+ if (!DECL_P (decl))
+ abort ();
+
if (DECL_P (decl))
{
if (DECL_PTA_TYPEVAR (decl))
return DECL_PTA_TYPEVAR (decl);
}
- entry.key = decl;
- result = htab_find (alias_annot, &entry);
- if (result != NULL && result->value != NULL)
- return result->value;
-
if (POINTER_TYPE_P (TREE_TYPE (decl))
&& TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == FUNCTION_TYPE)
@@ -932,16 +905,7 @@ create_alias_var (tree decl)
{
DECL_PTA_TYPEVAR (decl) = avar;
}
- else
- {
- newentry = ggc_alloc (sizeof (struct alias_annot_entry));
- newentry->key = decl;
- newentry->value = avar;
- slot =
- (struct alias_annot_entry **)htab_find_slot (alias_annot, newentry,
- INSERT);
- *slot = newentry;
- }
+
VARRAY_PUSH_GENERIC_PTR (alias_vars, avar);
ALIAS_TVAR_VARNUM (avar) = VARRAY_ACTIVE_SIZE (alias_vars) - 1;
return avar;
@@ -1021,26 +985,19 @@ void
delete_alias_vars (void)
{
size_t i;
- struct alias_annot_entry entry;
-
for (i = 0; i < VARRAY_ACTIVE_SIZE (local_alias_vars); i++)
{
- entry.key = VARRAY_TREE (local_alias_vars, i);
- if (!DECL_P (entry.key))
- {
- htab_remove_elt (alias_annot, &entry);
- }
+ tree key = VARRAY_TREE (local_alias_vars, i);
+ if (DECL_P (key))
+ DECL_PTA_TYPEVAR (key) = NULL;
else
- {
- DECL_PTA_TYPEVAR (entry.key) = NULL;
- }
+ abort ();
}
for (i = 0; i < VARRAY_ACTIVE_SIZE (local_alias_varnums); i ++)
VARRAY_GENERIC_PTR (alias_vars, VARRAY_INT (local_alias_varnums,
i)) = NULL;
if (!current_alias_ops->ip && !current_alias_ops->ip_partial)
{
- /* htab_delete (alias_annot); */
/* VARRAY_CLEAR (alias_vars); */
VARRAY_CLEAR (local_alias_vars);
VARRAY_CLEAR (local_alias_varnums);
@@ -1061,10 +1018,31 @@ init_alias_vars (void)
if ((!current_alias_ops->ip && !current_alias_ops->ip_partial)
|| alias_vars == NULL)
VARRAY_GENERIC_PTR_INIT (alias_vars, 10, "Alias vars");
- if ((!current_alias_ops->ip && !current_alias_ops->ip_partial)
- || alias_annot == NULL)
- alias_annot = htab_create_ggc (7, annot_hash, annot_eq, NULL);
+}
+
+/* Return true if PTR can't point to anything (i.e. it has an empty
+ points-to set. */
+bool
+empty_points_to_set (tree ptr)
+{
+ alias_typevar ptrtv;
+
+#if !FIELD_BASED
+#else
+ if (TREE_CODE (ptr) == COMPONENT_REF)
+ ptr = TREE_OPERAND (ptr, 1);
+#endif
+ if (DECL_P (ptr))
+ {
+ ptrtv = DECL_PTA_TYPEVAR (ptr);
+ if (!ptrtv)
+ return true;
+ }
+ else
+ abort ();
+
+ return current_alias_ops->empty_points_to_set (current_alias_ops,
ptrtv);
}
/* Return true if PTR and VAR have the same points-to set. */
@@ -1072,7 +1050,6 @@ init_alias_vars (void)
bool
same_points_to_set (tree ptr, tree var)
{
- struct alias_annot_entry entry, *result;
alias_typevar ptrtv, vartv;
#if !FIELD_BASED
@@ -1093,13 +1070,7 @@ same_points_to_set (tree ptr, tree var)
return false;
}
else
- {
- entry.key = ptr;
- result = htab_find (alias_annot, &entry);
- if (!result)
- return false;
- ptrtv = result->value;
- }
+ abort ();
if (DECL_P (var))
{
@@ -1108,14 +1079,8 @@ same_points_to_set (tree ptr, tree var)
return false;
}
else
- {
- entry.key = var;
- result = htab_find (alias_annot, &entry);
- if (!result)
- return false;
+ abort ();
- vartv = result->value;
- }
return current_alias_ops->same_points_to_set (current_alias_ops,
vartv, ptrtv);
}
@@ -1125,7 +1090,6 @@ same_points_to_set (tree ptr, tree var)
bool
ptr_may_alias_var (tree ptr, tree var)
{
- struct alias_annot_entry entry, *result;
alias_typevar ptrtv, vartv;
#if !FIELD_BASED
@@ -1146,13 +1110,7 @@ ptr_may_alias_var (tree ptr, tree var)
return false;
}
else
- {
- entry.key = ptr;
- result = htab_find (alias_annot, &entry);
- if (!result)
- return false;
- ptrtv = result->value;
- }
+ abort ();
if (DECL_P (var))
{
@@ -1161,14 +1119,7 @@ ptr_may_alias_var (tree ptr, tree var)
return false;
}
else
- {
- entry.key = var;
- result = htab_find (alias_annot, &entry);
- if (!result)
- return false;
-
- vartv = result->value;
- }
+ abort ();
return current_alias_ops->may_alias (current_alias_ops, ptrtv,
vartv);
}
Index: tree-alias-common.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-alias-common.h,v
retrieving revision 1.1.2.13
diff -u -3 -p -r1.1.2.13 tree-alias-common.h
--- tree-alias-common.h 30 Nov 2003 01:00:49 -0000 1.1.2.13
+++ tree-alias-common.h 28 Dec 2003 00:52:13 -0000
@@ -74,7 +74,10 @@ struct tree_alias_ops
/* Determine if two typevars have the same points-to set. */
bool (*same_points_to_set) (struct tree_alias_ops *, alias_typevar,
alias_typevar);
-
+
+ /* Determine if the typevar has an empty points-to set. */
+ bool (*empty_points_to_set) (struct tree_alias_ops *, alias_typevar);
+
/* Private data. */
void *data;
@@ -93,6 +96,6 @@ extern void delete_alias_vars (void);
extern void init_alias_vars (void);
extern bool ptr_may_alias_var (tree, tree);
extern bool same_points_to_set (tree, tree);
-
+extern bool empty_points_to_set (tree);
extern const char *alias_get_name (tree);
#endif
More information about the Gcc-patches
mailing list