This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[tree-ssa] Enable SSA CCP by default [patch]
- From: Diego Novillo <dnovillo at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 13 Nov 2002 16:12:39 -0500
- Subject: [tree-ssa] Enable SSA CCP by default [patch]
- Organization: Red Hat Canada
- Enables SSA CCP by default.
- Fixes a may-alias bug that was causing all the bootstrap
miscomparisons for the past several weeks. The dataflow
builder was not clobbering pointer dereferences at call sites.
*p = 5;
foo (p);
x = *p;
In the code above, the value 5 was being propagated across the
call to foo(). This was also creating a regression on
147.vortex in SPEC95.
- Adds a new test to catch this case.
The next obstacle is making sure that SSA information is kept
up-to-date or rebuilt so that we can chain passes. Right now,
another pass after CCP will likely fail. As a temporary kludge
we can tear down and rebuild CFG/DFA/SSA in
optimize_function_tree, but we need to move away from that model
in the long term.
Bootstrapped and tested on x86.
Diego.
* toplev.c (parse_options_and_default_flags): Enable SSA-CCP by
default with optimization >= 1.
* tree-dfa.c (find_refs_in_expr): Clobber '*.GLOBAL_VAR', not
'GLOBAL_VAR'.
(collect_dfa_stats): Collect statistics on '*.GLOBAL_VAR'.
(compute_may_aliases): Make sure that variable is an INDIRECT_REF.
(may_alias_p): GLOBAL_VAR should alias INDIRECT_REFs.
Only check addressability on VAR_DECLs.
(find_may_aliases_for): Make sure argument is an INDIRECT_REF.
* tree-flow-inline.h (indirect_var): Call DECL_P.
(set_indirect_var): Call DECL_P.
Create annotation if it doesn't exist.
(create_indirect_ref): Move from tree-dfa.c.
* tree-flow.h (create_indirect_ref): Declare.
* tree-ssa-ccp.c (visit_phi_node): Avoid debugging dump from
accessing uninitialized data.
* tree-ssa.c (init_tree_ssa): Create an INDIRECT_REF node for
.GLOBAL_VAR.
2002-11-13 Diego Novillo <dnovillo@redhat.com>
* testsuite/gcc.c-torture/execute/20021113-1.c: New test.
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.654.2.31
diff -d -u -p -r1.654.2.31 toplev.c
--- toplev.c 6 Nov 2002 12:21:04 -0000 1.654.2.31
+++ toplev.c 13 Nov 2002 19:51:54 -0000
@@ -4861,8 +4861,7 @@ parse_options_and_default_flags (argc, a
flag_crossjumping = 1;
flag_if_conversion = 1;
flag_if_conversion2 = 1;
- if (getenv ("TREE_CCP"))
- flag_tree_ccp = 1;
+ flag_tree_ccp = 1;
}
if (optimize >= 2)
Index: tree-dfa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-dfa.c,v
retrieving revision 1.1.4.46
diff -d -u -p -r1.1.4.46 tree-dfa.c
--- tree-dfa.c 12 Nov 2002 22:01:16 -0000 1.1.4.46
+++ tree-dfa.c 13 Nov 2002 19:51:54 -0000
@@ -100,7 +100,6 @@ static void find_may_aliases_for PARAMS
static void add_may_alias PARAMS ((tree, tree));
static inline bool may_alias_p PARAMS ((tree, tree));
static size_t tree_ref_size PARAMS ((enum tree_ref_type));
-static inline tree create_indirect_ref PARAMS ((tree));
static tree replace_ref_r PARAMS ((tree *, int *, void *));
@@ -387,11 +386,14 @@ find_refs_in_expr (expr_p, ref_type, ref
/* Function calls. Create a V_USE reference for every argument in the call.
If the callee is neither pure nor const, create a use and a def of
- GLOBAL_VAR. Definitions of this variable will reach uses of every call
- clobbered variable in the function. Uses of GLOBAL_VAR will be reached by
+ *.GLOBAL_VAR. This variable is a pointer that is assumed to point to
+ every global variable and locals that have had their address taken.
+
+ Definitions of this variable will reach uses of every call clobbered
+ variable in the function. Uses of *.GLOBAL_VAR will be reached by
definitions of call clobbered variables. This is used to model the
- effects that the called function may have on local and global variables
- that might be visible to it. */
+ effects that the called function may have on local and global
+ variables that might be visible to it. */
if (code == CALL_EXPR)
{
tree callee;
@@ -408,8 +410,10 @@ find_refs_in_expr (expr_p, ref_type, ref
may-use followed by a clobbering definition of GLOBAL_VAR. */
if (! (flags & (ECF_CONST | ECF_PURE)))
{
- create_ref (global_var, V_USE, TRM_MAY, bb, parent_stmt_p, 1);
- create_ref (global_var, V_DEF, TRM_CLOBBER, bb, parent_stmt_p, 1);
+ create_ref (indirect_var (global_var), V_USE, TRM_MAY, bb,
+ parent_stmt_p, 1);
+ create_ref (indirect_var (global_var), V_DEF, TRM_CLOBBER, bb,
+ parent_stmt_p, 1);
}
return;
@@ -1619,6 +1623,7 @@ collect_dfa_stats (dfa_stats_p)
htab_t htab;
tree *first_stmt_p;
basic_block bb;
+ tree star_global_var;
if (dfa_stats_p == NULL)
abort ();
@@ -1633,6 +1638,8 @@ collect_dfa_stats (dfa_stats_p)
/* Also look into GLOBAL_VAR (which is not actually part of the program). */
walk_tree (&global_var, collect_dfa_stats_r, (void *) dfa_stats_p, NULL);
+ star_global_var = indirect_var (global_var);
+ walk_tree (&star_global_var, collect_dfa_stats_r, (void *) dfa_stats_p, NULL);
FOR_EACH_BB (bb)
count_tree_refs (dfa_stats_p, bb_refs (bb));
@@ -1840,10 +1847,9 @@ compute_may_aliases ()
for (i = 0; i < num_referenced_vars; i++)
{
tree var = referenced_var (i);
- tree sym = get_base_symbol (var);
/* Find aliases for pointer variables. */
- if (POINTER_TYPE_P (TREE_TYPE (sym)))
+ if (TREE_CODE (var) == INDIRECT_REF)
find_may_aliases_for (var);
}
@@ -1856,39 +1862,41 @@ compute_may_aliases ()
}
-/* Return true if PTR (an INDIRECT_REF tree) may alias VAR_SYM (a _DECL tree).
- FIXME This returns true more often than it should. */
+/* Return true if INDIRECT_PTR (an INDIRECT_REF node) may alias VAR (a
+ VAR_DECL or INDIRECT_REF node). FIXME This returns true more often
+ than it should. */
static inline bool
-may_alias_p (ptr, var_sym)
- tree ptr;
- tree var_sym;
+may_alias_p (indirect_ptr, var)
+ tree indirect_ptr;
+ tree var;
{
HOST_WIDE_INT ptr_alias_set, var_alias_set;
- tree ptr_sym = get_base_symbol (ptr);
+ tree ptr_sym = get_base_symbol (indirect_ptr);
+ tree var_sym = get_base_symbol (var);
- /* GLOBAL_VAR aliases every global variable and locals that have had
- their address taken, unless points-to analysis is done. This is because
- points-to is supposed to handle this case, and thus, can give a more
- accurate answer. */
-
- if (!flag_tree_points_to &&
- ptr == global_var
- && var_sym != global_var
+ /* GLOBAL_VAR aliases every global variable, pointer dereference and
+ locals that have had their address taken, unless points-to analysis is
+ done. This is because points-to is supposed to handle this case, and
+ thus, can give a more accurate answer. */
+ if (flag_tree_points_to == PTA_NONE
+ && ptr_sym == global_var
&& (TREE_ADDRESSABLE (var_sym)
+ || TREE_CODE (var) == INDIRECT_REF
|| decl_function_context (var_sym) == NULL))
return true;
-
+
/* Obvious reasons why PTR_SYM and VAR_SYM can't possibly alias
each other. */
if (var_sym == ptr_sym
- || !POINTER_TYPE_P (TREE_TYPE (ptr_sym))
- || !TREE_ADDRESSABLE (var_sym)
- || DECL_ARTIFICIAL (var_sym))
+ || DECL_ARTIFICIAL (var_sym)
+ /* Only check for addressability on non-pointers. Even if VAR is
+ a non-addressable pointer, it may still alias with INDIRECT_PTR. */
+ || (DECL_P (var) && !TREE_ADDRESSABLE (var)))
return false;
- ptr_alias_set = get_alias_set (TREE_TYPE (ptr));
- var_alias_set = get_alias_set (TREE_TYPE (var_sym));
+ ptr_alias_set = get_alias_set (TREE_TYPE (indirect_ptr));
+ var_alias_set = get_alias_set (TREE_TYPE (var));
if (!alias_sets_conflict_p (ptr_alias_set, var_alias_set))
return false;
@@ -1901,25 +1909,31 @@ may_alias_p (ptr, var_sym)
}
-/* Find variables that PTR may be aliasing. */
+/* Find variables that INDIRECT_PTR (an INDIRECT_REF node) may be aliasing. */
static void
-find_may_aliases_for (ptr)
- tree ptr;
+find_may_aliases_for (indirect_ptr)
+ tree indirect_ptr;
{
unsigned long i;
+#if defined ENABLE_CHECKING
+ if (TREE_CODE (indirect_ptr) != INDIRECT_REF)
+ abort ();
+#endif
+
for (i = 0; i < num_referenced_vars; i++)
{
tree var = referenced_var (i);
- tree var_sym = get_base_symbol (var);
- if (may_alias_p (ptr, var_sym)
+ /* If *PTR may alias VAR, add *PTR to the list of may-aliases of VAR,
+ and VAR to the list of may-aliases of *PTR. */
+ if (may_alias_p (indirect_ptr, var)
/* Avoid adding duplicate aliases. */
- && get_alias_index (ptr, var_sym) == -1)
+ && get_alias_index (indirect_ptr, var) == -1)
{
- add_may_alias (ptr, var_sym);
- add_may_alias (var_sym, ptr);
+ add_may_alias (indirect_ptr, var);
+ add_may_alias (var, indirect_ptr);
}
}
}
@@ -2074,20 +2088,6 @@ tree_ref_structure (ref)
return TR_EXPR_REF_COMMON;
abort ();
-}
-
-
-/* Create and return a new INDIRECT_REF for pointer symbol PTR_SYM. */
-
-static inline tree
-create_indirect_ref (ptr_sym)
- tree ptr_sym;
-{
-#if defined ENABLE_CHECKING
- if (!POINTER_TYPE_P (TREE_TYPE (ptr_sym)))
- abort ();
-#endif
- return build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (ptr_sym)), ptr_sym);
}
Index: tree-flow-inline.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow-inline.h,v
retrieving revision 1.1.2.13
diff -d -u -p -r1.1.2.13 tree-flow-inline.h
--- tree-flow-inline.h 7 Nov 2002 15:55:35 -0000 1.1.2.13
+++ tree-flow-inline.h 13 Nov 2002 19:51:54 -0000
@@ -326,7 +326,7 @@ indirect_var (ptr)
tree ptr;
{
#if defined ENABLE_CHECKING
- if (TREE_CODE_CLASS (TREE_CODE (ptr)) != 'd'
+ if (!DECL_P (ptr)
|| !POINTER_TYPE_P (TREE_TYPE (ptr)))
abort ();
#endif
@@ -340,13 +340,24 @@ set_indirect_var (ptr, indirect)
{
tree_ann ann;
#if defined ENABLE_CHECKING
- if (TREE_CODE_CLASS (TREE_CODE (ptr)) != 'd'
+ if (!DECL_P (ptr)
|| !POINTER_TYPE_P (TREE_TYPE (ptr))
|| TREE_CODE (indirect) != INDIRECT_REF)
abort ();
#endif
- ann = tree_annotation (ptr);
+ ann = tree_annotation (ptr) ? tree_annotation (ptr) : create_tree_ann (ptr);
ann->indirect_var = indirect;
+}
+
+static inline tree
+create_indirect_ref (ptr_sym)
+ tree ptr_sym;
+{
+#if defined ENABLE_CHECKING
+ if (!POINTER_TYPE_P (TREE_TYPE (ptr_sym)))
+ abort ();
+#endif
+ return build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (ptr_sym)), ptr_sym);
}
static inline bb_ann
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow.h,v
retrieving revision 1.1.4.35
diff -d -u -p -r1.1.4.35 tree-flow.h
--- tree-flow.h 7 Nov 2002 15:55:35 -0000 1.1.4.35
+++ tree-flow.h 13 Nov 2002 19:51:54 -0000
@@ -528,6 +528,7 @@ static inline enum tree_flags tree_flags
static inline void reset_tree_flags PARAMS ((tree));
static inline tree indirect_var PARAMS ((tree));
static inline void set_indirect_var PARAMS ((tree, tree));
+static inline tree create_indirect_ref PARAMS ((tree));
static inline tree may_alias PARAMS ((tree, size_t));
static inline size_t num_may_alias PARAMS ((tree));
static inline int get_lineno PARAMS ((tree));
Index: tree-ssa-ccp.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-ccp.c,v
retrieving revision 1.1.2.31
diff -d -u -p -r1.1.2.31 tree-ssa-ccp.c
--- tree-ssa-ccp.c 8 Nov 2002 01:01:28 -0000 1.1.2.31
+++ tree-ssa-ccp.c 13 Nov 2002 19:51:55 -0000
@@ -348,14 +348,22 @@ visit_phi_node (phi_node)
if (e->flags & EDGE_EXECUTABLE)
{
tree_ref rdef;
- value rdef_val;
rdef = phi_arg_def (arg);
if (is_killing_def (rdef, phi_node))
{
+ value rdef_val;
+
rdef_val = values[ref_id (rdef)];
phi_val = cp_lattice_meet (phi_val, rdef_val);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ dump_ref (dump_file, "\t", phi_arg_def (arg), 0, 0);
+ dump_lattice_value (dump_file, "\tValue: ", rdef_val);
+ fprintf (dump_file, "\n");
+ }
}
else
{
@@ -364,13 +372,6 @@ visit_phi_node (phi_node)
its value to VARYING. */
phi_val.lattice_val = VARYING;
phi_val.const_value = NULL_TREE;
- }
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- dump_ref (dump_file, "\t", phi_arg_def (arg), 0, 0);
- dump_lattice_value (dump_file, "\tValue: ", rdef_val);
- fprintf (dump_file, "\n");
}
if (phi_val.lattice_val == VARYING)
Index: tree-ssa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa.c,v
retrieving revision 1.1.4.31
diff -d -u -p -r1.1.4.31 tree-ssa.c
--- tree-ssa.c 8 Nov 2002 01:01:28 -0000 1.1.4.31
+++ tree-ssa.c 13 Nov 2002 19:51:55 -0000
@@ -987,8 +987,10 @@ init_tree_ssa ()
DECL_EXTERNAL (global_var) = 0;
TREE_STATIC (global_var) = 0;
TREE_USED (global_var) = 1;
- DECL_CONTEXT (global_var) = 0;
+ DECL_CONTEXT (global_var) = NULL_TREE;
TREE_THIS_VOLATILE (global_var) = 1;
+ TREE_ADDRESSABLE (global_var) = 1;
+ set_indirect_var (global_var, create_indirect_ref (global_var));
/* If -Wuninitialized was used, set tree_warn_uninitialized and clear
warn_uninitialized to avoid duplicate warnings. */
Index: testsuite/gcc.c-torture/execute/20021113-1.c
===================================================================
RCS file: testsuite/gcc.c-torture/execute/20021113-1.c
diff -N testsuite/gcc.c-torture/execute/20021113-1.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.c-torture/execute/20021113-1.c 13 Nov 2002 19:52:00 -0000
@@ -0,0 +1,17 @@
+/* This program tests a data flow bug that would cause constant propagation
+ to propagate constants through function calls. */
+
+foo (int *p)
+{
+ *p = 10;
+}
+
+main()
+{
+ int *ptr = alloca (sizeof (int));
+ *ptr = 5;
+ foo (ptr);
+ if (*ptr == 5)
+ abort ();
+ exit (0);
+}