/* Alias analysis for trees.
- Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009
+ Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@redhat.com>
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
-#include "rtl.h"
#include "tm_p.h"
-#include "hard-reg-set.h"
#include "basic-block.h"
#include "timevar.h"
#include "expr.h"
#include "flags.h"
#include "function.h"
#include "diagnostic.h"
+#include "tree-pretty-print.h"
#include "tree-dump.h"
#include "gimple.h"
#include "tree-flow.h"
ptr = TREE_OPERAND (base, 0);
else if (base
&& SSA_VAR_P (base))
- return operand_equal_p (base, decl, 0);
+ return base == decl;
else if (base
&& CONSTANT_CLASS_P (base))
return false;
if (DECL_RESTRICTED_P (decl)
&& TYPE_RESTRICT (TREE_TYPE (ptr))
&& pi->pt.vars_contains_restrict)
- return bitmap_bit_p (pi->pt.vars, DECL_UID (decl));
+ return bitmap_bit_p (pi->pt.vars, DECL_PT_UID (decl));
return pt_solution_includes (&pi->pt, decl);
}
fprintf (file, "\nESCAPED");
dump_points_to_solution (file, &cfun->gimple_df->escaped);
- fprintf (file, "\nCALLUSED");
- dump_points_to_solution (file, &cfun->gimple_df->callused);
fprintf (file, "\n\nFlow-insensitive points-to information\n\n");
if (pt->escaped)
fprintf (file, ", points-to escaped");
+ if (pt->ipa_escaped)
+ fprintf (file, ", points-to unit escaped");
+
if (pt->null)
fprintf (file, ", points-to NULL");
dump_decl_set (file, pt->vars);
if (pt->vars_contains_global)
fprintf (file, " (includes global vars)");
+ if (pt->vars_contains_restrict)
+ fprintf (file, " (includes restrict tags)");
}
}
&& TREE_CODE (type2) == ARRAY_TYPE)
return -1;
- /* In Ada, an lvalue of unconstrained type can be used to access an object
- of one of its constrained subtypes, for example when a function with an
- unconstrained parameter passed by reference is called on a constrained
- object and inlined. In this case, the types have the same alias set. */
- if (TYPE_SIZE (type1) && TYPE_SIZE (type2)
- && TREE_CONSTANT (TYPE_SIZE (type1)) != TREE_CONSTANT (TYPE_SIZE (type2))
- && get_alias_set (type1) == get_alias_set (type2))
+ /* ??? In Ada, an lvalue of an unconstrained type can be used to access an
+ object of one of its constrained subtypes, e.g. when a function with an
+ unconstrained parameter passed by reference is called on an object and
+ inlined. But, even in the case of a fixed size, type and subtypes are
+ not equivalent enough as to share the same TYPE_CANONICAL, since this
+ would mean that conversions between them are useless, whereas they are
+ not (e.g. type and subtypes can have different modes). So, in the end,
+ they are only guaranteed to have the same alias set. */
+ if (get_alias_set (type1) == get_alias_set (type2))
return -1;
/* The types are known to be not equal. */
gcc_assert (SSA_VAR_P (base1) && SSA_VAR_P (base2));
/* If both references are based on different variables, they cannot alias. */
- if (!operand_equal_p (base1, base2, 0))
+ if (base1 != base2)
return false;
/* If both references are based on the same variable, they cannot alias if
return decl_refs_may_alias_p (base1, offset1, max_size1,
base2, offset2, max_size2);
+ ind1_p = INDIRECT_REF_P (base1);
+ ind2_p = INDIRECT_REF_P (base2);
+ /* Canonicalize the pointer-vs-decl case. */
+ if (ind1_p && var2_p)
+ {
+ HOST_WIDE_INT tmp1;
+ tree tmp2;
+ ao_ref *tmp3;
+ tmp1 = offset1; offset1 = offset2; offset2 = tmp1;
+ tmp1 = max_size1; max_size1 = max_size2; max_size2 = tmp1;
+ tmp2 = base1; base1 = base2; base2 = tmp2;
+ tmp3 = ref1; ref1 = ref2; ref2 = tmp3;
+ var1_p = true;
+ ind1_p = false;
+ var2_p = false;
+ ind2_p = true;
+ }
+
+ /* If we are about to disambiguate pointer-vs-decl try harder to
+ see must-aliases and give leeway to some invalid cases.
+ This covers a pretty minimal set of cases only and does not
+ when called from the RTL oracle. It handles cases like
+
+ int i = 1;
+ return *(float *)&i;
+
+ and also fixes gfortran.dg/lto/pr40725. */
+ if (var1_p && ind2_p
+ && cfun
+ && gimple_in_ssa_p (cfun)
+ && TREE_CODE (TREE_OPERAND (base2, 0)) == SSA_NAME)
+ {
+ gimple def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (base2, 0));
+ while (is_gimple_assign (def_stmt)
+ && (gimple_assign_rhs_code (def_stmt) == SSA_NAME
+ || CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt))))
+ {
+ tree rhs = gimple_assign_rhs1 (def_stmt);
+ HOST_WIDE_INT offset, size, max_size;
+
+ /* Look through SSA name copies and pointer conversions. */
+ if (TREE_CODE (rhs) == SSA_NAME
+ && POINTER_TYPE_P (TREE_TYPE (rhs)))
+ {
+ def_stmt = SSA_NAME_DEF_STMT (rhs);
+ continue;
+ }
+ if (TREE_CODE (rhs) != ADDR_EXPR)
+ break;
+
+ /* If the pointer is defined as an address based on a decl
+ use plain offset disambiguation and ignore TBAA. */
+ rhs = TREE_OPERAND (rhs, 0);
+ rhs = get_ref_base_and_extent (rhs, &offset, &size, &max_size);
+ if (SSA_VAR_P (rhs))
+ {
+ base2 = rhs;
+ offset2 += offset;
+ if (size != max_size
+ || max_size == -1)
+ max_size2 = -1;
+ return decl_refs_may_alias_p (base1, offset1, max_size1,
+ base2, offset2, max_size2);
+ }
+
+ /* Do not continue looking through &p->x to limit time
+ complexity. */
+ break;
+ }
+ }
+
/* First defer to TBAA if possible. */
if (tbaa_p
&& flag_strict_aliasing
return true;
/* Dispatch to the pointer-vs-decl or pointer-vs-pointer disambiguators. */
- ind1_p = INDIRECT_REF_P (base1);
- ind2_p = INDIRECT_REF_P (base2);
set = tbaa_p ? -1 : 0;
if (var1_p && ind2_p)
return indirect_ref_may_alias_decl_p (ref2->ref, TREE_OPERAND (base2, 0),
offset2, max_size2, set,
ref1->ref, base1,
offset1, max_size1, set);
- else if (ind1_p && var2_p)
- return indirect_ref_may_alias_decl_p (ref1->ref, TREE_OPERAND (base1, 0),
- offset1, max_size1, set,
- ref2->ref, base2,
- offset2, max_size2, set);
else if (ind1_p && ind2_p)
return indirect_refs_may_alias_p (ref1->ref, TREE_OPERAND (base1, 0),
offset1, max_size1, set,
/* 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_STATIC (base))
{
bitmap not_read;
goto process_args;
}
- /* If the base variable is call-used or call-clobbered then
- it may be used. */
- if (flags & (ECF_PURE|ECF_CONST|ECF_LOOPING_CONST_OR_PURE|ECF_NOVOPS))
+ /* Check if the base variable is call-used. */
+ if (DECL_P (base))
{
- if (DECL_P (base))
- {
- if (is_call_used (base))
- return true;
- }
- else if (INDIRECT_REF_P (base)
- && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
- {
- struct ptr_info_def *pi = SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0));
- if (!pi)
- return true;
-
- if (pt_solution_includes_global (&pi->pt)
- || pt_solutions_intersect (&cfun->gimple_df->callused, &pi->pt)
- || pt_solutions_intersect (&cfun->gimple_df->escaped, &pi->pt))
- return true;
- }
- else
+ if (pt_solution_includes (gimple_call_use_set (call), base))
return true;
}
- else
+ else if (INDIRECT_REF_P (base)
+ && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
{
- if (DECL_P (base))
- {
- if (is_call_clobbered (base))
- return true;
- }
- else if (INDIRECT_REF_P (base)
- && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
- {
- struct ptr_info_def *pi = SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0));
- if (!pi)
- return true;
+ struct ptr_info_def *pi = SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0));
+ if (!pi)
+ return true;
- if (pt_solution_includes_global (&pi->pt)
- || pt_solutions_intersect (&cfun->gimple_df->escaped, &pi->pt))
- return true;
- }
- else
+ if (pt_solutions_intersect (gimple_call_use_set (call), &pi->pt))
return true;
}
+ else
+ return true;
/* Inspect call arguments for passed-by-value aliases. */
process_args:
for (i = 0; i < gimple_call_num_args (call); ++i)
{
tree op = gimple_call_arg (call, i);
+ int flags = gimple_call_arg_flags (call, i);
+
+ if (flags & EAF_UNUSED)
+ continue;
if (TREE_CODE (op) == WITH_SIZE_EXPR)
op = TREE_OPERAND (op, 0);
case BUILT_IN_CALLOC:
/* Unix98 specifies that errno is set on allocation failure.
Until we properly can track the errno location assume it
- is not a plain decl but anonymous storage in a different
- translation unit. */
- if (flag_errno_math)
+ is not a local decl but external or anonymous storage in
+ a different translation unit. Also assume it is of
+ type int as required by the standard. */
+ if (flag_errno_math
+ && TREE_TYPE (base) == integer_type_node)
{
struct ptr_info_def *pi;
- if (DECL_P (base))
- return false;
- if (INDIRECT_REF_P (base)
- && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME
- && (pi = SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0))))
+ if (DECL_P (base)
+ && !TREE_STATIC (base))
+ return true;
+ else if (INDIRECT_REF_P (base)
+ && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME
+ && (pi = SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0))))
return pi->pt.anything || pi->pt.nonlocal;
}
return false;
by the function. */
if (callee != NULL_TREE
&& TREE_CODE (base) == VAR_DECL
- && TREE_STATIC (base)
- && !TREE_PUBLIC (base))
+ && TREE_STATIC (base))
{
bitmap not_written;
return false;
}
+ /* Check if the base variable is call-clobbered. */
if (DECL_P (base))
- return is_call_clobbered (base);
+ return pt_solution_includes (gimple_call_clobber_set (call), base);
else if (INDIRECT_REF_P (base)
&& TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
{
if (!pi)
return true;
- return (pt_solution_includes_global (&pi->pt)
- || pt_solutions_intersect (&cfun->gimple_df->escaped, &pi->pt));
+ return pt_solutions_intersect (gimple_call_clobber_set (call), &pi->pt);
}
return true;
}
-static bool ATTRIBUTE_UNUSED
+/* If the call in statement CALL may clobber the memory reference REF
+ return true, otherwise return false. */
+
+bool
call_may_clobber_ref_p (gimple call, tree ref)
{
bool res;