diff options
author | Richard Guenther <rguenther@suse.de> | 2009-06-19 16:47:35 +0000 |
---|---|---|
committer | Richard Biener <rguenth@gcc.gnu.org> | 2009-06-19 16:47:35 +0000 |
commit | 779704e7cf116eb261248a30d8b7d57157532a58 (patch) | |
tree | 115043f9abcfc58fee3a9e901196c7d3eba9702f /gcc/tree-ssa-alias.c | |
parent | 217655da6f8d9c11e77452d5b4ed421205716bac (diff) | |
download | gcc-779704e7cf116eb261248a30d8b7d57157532a58.zip gcc-779704e7cf116eb261248a30d8b7d57157532a58.tar.gz gcc-779704e7cf116eb261248a30d8b7d57157532a58.tar.bz2 |
tree-ssa-alias.c (ptr_deref_may_alias_decl_p): Handle ADDR_EXPR pointers.
2009-06-19 Richard Guenther <rguenther@suse.de>
* tree-ssa-alias.c (ptr_deref_may_alias_decl_p): Handle
ADDR_EXPR pointers.
(ptr_derefs_may_alias_p): Likewise.
(ptr_deref_may_alias_ref_p_1): New function.
(ptr_deref_may_alias_ref_p): Likewise.
(ref_maybe_used_by_call_p_1): Handle builtins that are not
covered by looking at the ESCAPED solution.
(call_may_clobber_ref_p_1): Likewise.
* tree-ssa-structalias.c (get_constraint_for_ptr_offset):
Handle NULL_TREE offset. Do not produce redundant constraints.
(process_all_all_constraints): New helper function.
(do_structure_copy): Use it.
(handle_lhs_call): Likewise.
(find_func_aliases): Handle some builtins with pointer arguments
and/or return values explicitly.
* gcc.c-torture/execute/20090618-1.c: New testcase.
From-SVN: r148718
Diffstat (limited to 'gcc/tree-ssa-alias.c')
-rw-r--r-- | gcc/tree-ssa-alias.c | 217 |
1 files changed, 193 insertions, 24 deletions
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 6cbec5d..c83488b 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -168,14 +168,9 @@ ptr_deref_may_alias_decl_p (tree ptr, tree decl) { struct ptr_info_def *pi; - /* ??? During SCCVN/PRE we can end up with *&x during valueizing - operands. Likewise we can end up with dereferencing constant - pointers. Just bail out in these cases for now. */ - if (TREE_CODE (ptr) == ADDR_EXPR - || TREE_CODE (ptr) == INTEGER_CST) - return true; - - gcc_assert (TREE_CODE (ptr) == SSA_NAME + gcc_assert ((TREE_CODE (ptr) == SSA_NAME + || TREE_CODE (ptr) == ADDR_EXPR + || TREE_CODE (ptr) == INTEGER_CST) && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == RESULT_DECL)); @@ -184,6 +179,29 @@ ptr_deref_may_alias_decl_p (tree ptr, tree decl) if (!may_be_aliased (decl)) return false; + /* ADDR_EXPR pointers either just offset another pointer or directly + specify the pointed-to set. */ + if (TREE_CODE (ptr) == ADDR_EXPR) + { + tree base = get_base_address (TREE_OPERAND (ptr, 0)); + if (base + && INDIRECT_REF_P (base)) + ptr = TREE_OPERAND (base, 0); + else if (base + && SSA_VAR_P (base)) + return operand_equal_p (base, decl, 0); + else if (base + && CONSTANT_CLASS_P (base)) + return false; + else + return true; + } + + /* We can end up with dereferencing constant pointers. + Just bail out in this case. */ + if (TREE_CODE (ptr) == INTEGER_CST) + return true; + /* If we do not have useful points-to information for this pointer we cannot disambiguate anything else. */ pi = SSA_NAME_PTR_INFO (ptr); @@ -202,18 +220,46 @@ ptr_derefs_may_alias_p (tree ptr1, tree ptr2) { struct ptr_info_def *pi1, *pi2; - /* ??? During SCCVN/PRE we can end up with *&x during valueizing - operands. Likewise we can end up with dereferencing constant - pointers. Just bail out in these cases for now. */ - if (TREE_CODE (ptr1) == ADDR_EXPR - || TREE_CODE (ptr1) == INTEGER_CST - || TREE_CODE (ptr2) == ADDR_EXPR + gcc_assert ((TREE_CODE (ptr1) == SSA_NAME + || TREE_CODE (ptr1) == ADDR_EXPR + || TREE_CODE (ptr1) == INTEGER_CST) + && (TREE_CODE (ptr2) == SSA_NAME + || TREE_CODE (ptr2) == ADDR_EXPR + || TREE_CODE (ptr2) == INTEGER_CST)); + + /* ADDR_EXPR pointers either just offset another pointer or directly + specify the pointed-to set. */ + if (TREE_CODE (ptr1) == ADDR_EXPR) + { + tree base = get_base_address (TREE_OPERAND (ptr1, 0)); + if (base + && INDIRECT_REF_P (base)) + ptr1 = TREE_OPERAND (base, 0); + else if (base + && SSA_VAR_P (base)) + return ptr_deref_may_alias_decl_p (ptr2, base); + else + return true; + } + if (TREE_CODE (ptr2) == ADDR_EXPR) + { + tree base = get_base_address (TREE_OPERAND (ptr2, 0)); + if (base + && INDIRECT_REF_P (base)) + ptr2 = TREE_OPERAND (base, 0); + else if (base + && SSA_VAR_P (base)) + return ptr_deref_may_alias_decl_p (ptr1, base); + else + return true; + } + + /* We can end up with dereferencing constant pointers. + Just bail out in this case. */ + if (TREE_CODE (ptr1) == INTEGER_CST || TREE_CODE (ptr2) == INTEGER_CST) return true; - gcc_assert (TREE_CODE (ptr1) == SSA_NAME - && TREE_CODE (ptr2) == SSA_NAME); - /* We may end up with two empty points-to solutions for two same pointers. In this case we still want to say both pointers alias, so shortcut that here. */ @@ -232,6 +278,31 @@ ptr_derefs_may_alias_p (tree ptr1, tree ptr2) return pt_solutions_intersect (&pi1->pt, &pi2->pt); } +/* Return true if dereferencing PTR may alias *REF. + The caller is responsible for applying TBAA to see if PTR + may access *REF at all. */ + +static bool +ptr_deref_may_alias_ref_p_1 (tree ptr, ao_ref *ref) +{ + tree base = ao_ref_base (ref); + + if (INDIRECT_REF_P (base)) + return ptr_derefs_may_alias_p (ptr, TREE_OPERAND (base, 0)); + else if (SSA_VAR_P (base)) + return ptr_deref_may_alias_decl_p (ptr, base); + + return true; +} + +static bool +ptr_deref_may_alias_ref_p (tree ptr, tree ref) +{ + ao_ref r; + ao_ref_init (&r, ref); + return ptr_deref_may_alias_ref_p_1 (ptr, &r); +} + /* Dump alias information on FILE. */ @@ -778,7 +849,7 @@ refs_output_dependent_p (tree store1, tree store2) static bool ref_maybe_used_by_call_p_1 (gimple call, tree ref) { - tree base; + tree base, callee; unsigned i; int flags = gimple_call_flags (call); @@ -803,13 +874,41 @@ ref_maybe_used_by_call_p_1 (gimple call, tree ref) && !is_global_var (base)) goto process_args; + callee = gimple_call_fndecl (call); + + /* Handle those builtin functions explicitly that do not act as + escape points. See tree-ssa-structalias.c:find_func_aliases + for the list of builtins we might need to handle here. */ + if (callee != NULL_TREE + && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL) + switch (DECL_FUNCTION_CODE (callee)) + { + /* All the following functions clobber memory pointed to by + their first argument. */ + case BUILT_IN_STRCPY: + case BUILT_IN_STRNCPY: + case BUILT_IN_BCOPY: + case BUILT_IN_MEMCPY: + case BUILT_IN_MEMMOVE: + case BUILT_IN_MEMPCPY: + case BUILT_IN_STPCPY: + case BUILT_IN_STPNCPY: + case BUILT_IN_STRCAT: + case BUILT_IN_STRNCAT: + { + tree src = gimple_call_arg (call, 1); + return ptr_deref_may_alias_ref_p (src, ref); + } + default: + /* Fallthru to general call handling. */; + } + /* Check if base is a global static variable that is not read by the function. */ if (TREE_CODE (base) == VAR_DECL && TREE_STATIC (base) && !TREE_PUBLIC (base)) { - tree callee = gimple_call_fndecl (call); bitmap not_read; if (callee != NULL_TREE @@ -901,6 +1000,7 @@ static bool call_may_clobber_ref_p_1 (gimple call, ao_ref *ref) { tree base; + tree callee; /* If the call is pure or const it cannot clobber anything. */ if (gimple_call_flags (call) @@ -926,18 +1026,87 @@ call_may_clobber_ref_p_1 (gimple call, ao_ref *ref) || !is_global_var (base))) return false; + callee = gimple_call_fndecl (call); + + /* Handle those builtin functions explicitly that do not act as + escape points. See tree-ssa-structalias.c:find_func_aliases + for the list of builtins we might need to handle here. */ + if (callee != NULL_TREE + && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL) + switch (DECL_FUNCTION_CODE (callee)) + { + /* All the following functions clobber memory pointed to by + their first argument. */ + case BUILT_IN_STRCPY: + case BUILT_IN_STRNCPY: + case BUILT_IN_BCOPY: + case BUILT_IN_MEMCPY: + case BUILT_IN_MEMMOVE: + case BUILT_IN_MEMPCPY: + case BUILT_IN_STPCPY: + case BUILT_IN_STPNCPY: + case BUILT_IN_STRCAT: + case BUILT_IN_STRNCAT: + { + tree dest = gimple_call_arg (call, 0); + return ptr_deref_may_alias_ref_p_1 (dest, ref); + } + /* Freeing memory kills the pointed-to memory. More importantly + the call has to serve as a barrier for moving loads and stores + across it. Same is true for memset. */ + case BUILT_IN_FREE: + case BUILT_IN_MEMSET: + { + tree ptr = gimple_call_arg (call, 0); + return ptr_deref_may_alias_ref_p_1 (ptr, ref); + } + case BUILT_IN_FREXP: + case BUILT_IN_FREXPF: + case BUILT_IN_FREXPL: + case BUILT_IN_GAMMA_R: + case BUILT_IN_GAMMAF_R: + case BUILT_IN_GAMMAL_R: + case BUILT_IN_LGAMMA_R: + case BUILT_IN_LGAMMAF_R: + case BUILT_IN_LGAMMAL_R: + case BUILT_IN_MODF: + case BUILT_IN_MODFF: + case BUILT_IN_MODFL: + { + tree out = gimple_call_arg (call, 1); + return ptr_deref_may_alias_ref_p_1 (out, ref); + } + case BUILT_IN_REMQUO: + case BUILT_IN_REMQUOF: + case BUILT_IN_REMQUOL: + { + tree out = gimple_call_arg (call, 2); + return ptr_deref_may_alias_ref_p_1 (out, ref); + } + case BUILT_IN_SINCOS: + case BUILT_IN_SINCOSF: + case BUILT_IN_SINCOSL: + { + tree sin = gimple_call_arg (call, 1); + tree cos = gimple_call_arg (call, 2); + return (ptr_deref_may_alias_ref_p_1 (sin, ref) + || ptr_deref_may_alias_ref_p_1 (cos, ref)); + } + default: + /* Fallthru to general call handling. */; + } + /* Check if base is a global static variable that is not written by the function. */ - if (TREE_CODE (base) == VAR_DECL + if (callee != NULL_TREE + && TREE_CODE (base) == VAR_DECL && TREE_STATIC (base) && !TREE_PUBLIC (base)) { - tree callee = gimple_call_fndecl (call); bitmap not_written; - if (callee != NULL_TREE - && (not_written - = ipa_reference_get_not_written_global (cgraph_node (callee))) + if ((not_written + = ipa_reference_get_not_written_global (cgraph_node (callee))) && bitmap_bit_p (not_written, DECL_UID (base))) return false; } |