/* Alias analysis for trees.
- Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@redhat.com>
alias_set_type base2_alias_set, bool tbaa_p)
{
tree ptr1;
- tree ptrtype1;
+ tree ptrtype1, dbase2;
HOST_WIDE_INT offset1p = offset1, offset2p = offset2;
+ HOST_WIDE_INT doffset1, doffset2;
double_int moff;
gcc_checking_assert ((TREE_CODE (base1) == MEM_REF
the pointer access is beyond the extent of the variable access.
(the pointer base cannot validly point to an offset less than zero
of the variable).
- They also cannot alias if the pointer may not point to the decl. */
- if ((TREE_CODE (base1) != TARGET_MEM_REF
- || (!TMR_INDEX (base1) && !TMR_INDEX2 (base1)))
+ ??? IVOPTs creates bases that do not honor this restriction,
+ so do not apply this optimization for TARGET_MEM_REFs. */
+ if (TREE_CODE (base1) != TARGET_MEM_REF
&& !ranges_overlap_p (MAX (0, offset1p), -1, offset2p, max_size2))
return false;
+ /* They also cannot alias if the pointer may not point to the decl. */
if (!ptr_deref_may_alias_decl_p (ptr1, base2))
return false;
if (base2_alias_set == -1)
base2_alias_set = get_alias_set (base2);
- /* If both references are through the same type, they do not alias
- if the accesses do not overlap. This does extra disambiguation
- for mixed/pointer accesses but requires strict aliasing.
- For MEM_REFs we require that the component-ref offset we computed
- is relative to the start of the type which we ensure by
- comparing rvalue and access type and disregarding the constant
- pointer offset. */
- if ((TREE_CODE (base1) != TARGET_MEM_REF
- || (!TMR_INDEX (base1) && !TMR_INDEX2 (base1)))
- && (TREE_CODE (base1) != MEM_REF
- || same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (ptrtype1)) == 1)
- && same_type_for_tbaa (TREE_TYPE (ptrtype1), TREE_TYPE (base2)) == 1)
- return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
-
/* When we are trying to disambiguate an access with a pointer dereference
as base versus one with a decl as base we can use both the size
of the decl and its dynamic type for extra disambiguation.
&& tree_int_cst_lt (DECL_SIZE (base2), TYPE_SIZE (TREE_TYPE (ptrtype1))))
return false;
+ if (!ref2)
+ return true;
+
+ /* If the decl is accessed via a MEM_REF, reconstruct the base
+ we can use for TBAA and an appropriately adjusted offset. */
+ dbase2 = ref2;
+ while (handled_component_p (dbase2))
+ dbase2 = TREE_OPERAND (dbase2, 0);
+ doffset1 = offset1;
+ doffset2 = offset2;
+ if (TREE_CODE (dbase2) == MEM_REF
+ || TREE_CODE (dbase2) == TARGET_MEM_REF)
+ {
+ double_int moff = mem_ref_offset (dbase2);
+ moff = double_int_lshift (moff,
+ BITS_PER_UNIT == 8
+ ? 3 : exact_log2 (BITS_PER_UNIT),
+ HOST_BITS_PER_DOUBLE_INT, true);
+ if (double_int_negative_p (moff))
+ doffset1 -= double_int_neg (moff).low;
+ else
+ doffset2 -= moff.low;
+ }
+
+ /* If either reference is view-converted, give up now. */
+ if (same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (ptrtype1)) != 1
+ || same_type_for_tbaa (TREE_TYPE (dbase2),
+ TREE_TYPE (reference_alias_ptr_type (dbase2))) != 1)
+ return true;
+
+ /* If both references are through the same type, they do not alias
+ if the accesses do not overlap. This does extra disambiguation
+ for mixed/pointer accesses but requires strict aliasing.
+ For MEM_REFs we require that the component-ref offset we computed
+ is relative to the start of the type which we ensure by
+ comparing rvalue and access type and disregarding the constant
+ pointer offset. */
+ if ((TREE_CODE (base1) != TARGET_MEM_REF
+ || (!TMR_INDEX (base1) && !TMR_INDEX2 (base1)))
+ && same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (dbase2)) == 1)
+ return ranges_overlap_p (doffset1, max_size1, doffset2, max_size2);
+
/* Do access-path based disambiguation. */
if (ref1 && ref2
- && handled_component_p (ref1)
- && handled_component_p (ref2)
- && TREE_CODE (base1) != TARGET_MEM_REF
- && (TREE_CODE (base1) != MEM_REF
- || same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (ptrtype1)) == 1))
+ && (handled_component_p (ref1) || handled_component_p (ref2)))
return aliasing_component_refs_p (ref1,
ref1_alias_set, base1_alias_set,
offset1, max_size1,
size);
return refs_may_alias_p_1 (&dref, ref, false);
}
+ case BUILT_IN_STRCPY_CHK:
+ case BUILT_IN_STRNCPY_CHK:
+ case BUILT_IN_MEMCPY_CHK:
+ case BUILT_IN_MEMMOVE_CHK:
+ case BUILT_IN_MEMPCPY_CHK:
+ case BUILT_IN_STPCPY_CHK:
+ case BUILT_IN_STRCAT_CHK:
+ case BUILT_IN_STRNCAT_CHK:
+ {
+ ao_ref dref;
+ tree size = NULL_TREE;
+ if (gimple_call_num_args (call) == 4)
+ size = gimple_call_arg (call, 2);
+ ao_ref_init_from_ptr_and_size (&dref,
+ gimple_call_arg (call, 1),
+ size);
+ return refs_may_alias_p_1 (&dref, ref, false);
+ }
case BUILT_IN_BCOPY:
{
ao_ref dref;
case BUILT_IN_STACK_SAVE:
case BUILT_IN_STACK_RESTORE:
case BUILT_IN_MEMSET:
+ case BUILT_IN_MEMSET_CHK:
case BUILT_IN_FREXP:
case BUILT_IN_FREXPF:
case BUILT_IN_FREXPL:
case BUILT_IN_SINCOS:
case BUILT_IN_SINCOSF:
case BUILT_IN_SINCOSL:
+ case BUILT_IN_ASSUME_ALIGNED:
return false;
/* __sync_* builtins and some OpenMP builtins act as threading
barriers. */
size);
return refs_may_alias_p_1 (&dref, ref, false);
}
+ case BUILT_IN_STRCPY_CHK:
+ case BUILT_IN_STRNCPY_CHK:
+ case BUILT_IN_MEMCPY_CHK:
+ case BUILT_IN_MEMMOVE_CHK:
+ case BUILT_IN_MEMPCPY_CHK:
+ case BUILT_IN_STPCPY_CHK:
+ case BUILT_IN_STRCAT_CHK:
+ case BUILT_IN_STRNCAT_CHK:
+ case BUILT_IN_MEMSET_CHK:
+ {
+ ao_ref dref;
+ tree size = NULL_TREE;
+ if (gimple_call_num_args (call) == 4)
+ size = gimple_call_arg (call, 2);
+ ao_ref_init_from_ptr_and_size (&dref,
+ gimple_call_arg (call, 0),
+ size);
+ return refs_may_alias_p_1 (&dref, ref, false);
+ }
case BUILT_IN_BCOPY:
{
ao_ref dref;
return false;
case BUILT_IN_STACK_SAVE:
case BUILT_IN_ALLOCA:
+ case BUILT_IN_ASSUME_ALIGNED:
return false;
/* Freeing memory kills the pointed-to memory. More importantly
the call has to serve as a barrier for moving loads and stores
return false;
if (gimple_has_lhs (stmt)
- && TREE_CODE (gimple_get_lhs (stmt)) != SSA_NAME)
+ && TREE_CODE (gimple_get_lhs (stmt)) != SSA_NAME
+ /* The assignment is not necessarily carried out if it can throw
+ and we can catch it in the current function where we could inspect
+ the previous value.
+ ??? We only need to care about the RHS throwing. For aggregate
+ assignments or similar calls and non-call exceptions the LHS
+ might throw as well. */
+ && !stmt_can_throw_internal (stmt))
{
tree base, lhs = gimple_get_lhs (stmt);
HOST_WIDE_INT size, offset, max_size;
case BUILT_IN_MEMPCPY:
case BUILT_IN_MEMMOVE:
case BUILT_IN_MEMSET:
+ case BUILT_IN_MEMCPY_CHK:
+ case BUILT_IN_MEMPCPY_CHK:
+ case BUILT_IN_MEMMOVE_CHK:
+ case BUILT_IN_MEMSET_CHK:
{
tree dest = gimple_call_arg (stmt, 0);
tree len = gimple_call_arg (stmt, 2);