/* Alias analysis for GNU C
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- 2007, 2008, 2009 Free Software Foundation, Inc.
+ 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
Contributed by John Carr (jfc@mit.edu).
This file is part of GCC.
if (!expr)
return false;
- /* If MEM_OFFSET or MEM_SIZE are NULL punt. */
- if (!MEM_OFFSET (mem)
- || !MEM_SIZE (mem))
- return false;
-
ao_ref_init (ref, expr);
/* Get the base of the reference and see if we have to reject or
if (base == NULL_TREE)
return false;
+ /* The tree oracle doesn't like to have these. */
+ if (TREE_CODE (base) == FUNCTION_DECL
+ || TREE_CODE (base) == LABEL_DECL)
+ return false;
+
/* If this is a pointer dereference of a non-SSA_NAME punt.
??? We could replace it with a pointer to anything. */
if (INDIRECT_REF_P (base)
&& TREE_CODE (TREE_OPERAND (base, 0)) != SSA_NAME)
return false;
- /* The tree oracle doesn't like to have these. */
- if (TREE_CODE (base) == FUNCTION_DECL
- || TREE_CODE (base) == LABEL_DECL)
- return false;
-
/* If this is a reference based on a partitioned decl replace the
base with an INDIRECT_REF of the pointer representative we
created during stack slot partitioning. */
ref->ref_alias_set = MEM_ALIAS_SET (mem);
+ /* If MEM_OFFSET or MEM_SIZE are NULL we have to punt.
+ Keep points-to related information though. */
+ if (!MEM_OFFSET (mem)
+ || !MEM_SIZE (mem))
+ {
+ ref->ref = NULL_TREE;
+ ref->offset = 0;
+ ref->size = -1;
+ ref->max_size = -1;
+ return true;
+ }
+
/* If the base decl is a parameter we can have negative MEM_OFFSET in
case of promoted subregs on bigendian targets. Trust the MEM_EXPR
here. */
/* Otherwise, check if set1 is a subset of set2. */
ase = get_alias_set_entry (set2);
if (ase != 0
- && ((ase->has_zero_child && set1 == 0)
+ && (ase->has_zero_child
|| splay_tree_lookup (ase->children,
(splay_tree_key) set1)))
return true;
|| (GET_CODE (y_base) == ADDRESS && GET_MODE (y_base) == Pmode))
return 0;
- if (! flag_argument_noalias)
- return 1;
-
- if (flag_argument_noalias > 1)
- return 0;
-
- /* Weak noalias assertion (arguments are distinct, but may match globals). */
- return ! (GET_MODE (x_base) == VOIDmode && GET_MODE (y_base) == VOIDmode);
+ return 1;
}
/* Convert the address X into something we can use. This is done by returning
return addr;
}
-/* Return nonzero if X and Y (memory addresses) could reference the
- same location in memory. C is an offset accumulator. When
+/* Return one if X and Y (memory addresses) reference the
+ same location in memory or if the references overlap.
+ Return zero if they do not overlap, else return
+ minus one in which case they still might reference the same location.
+
+ C is an offset accumulator. When
C is nonzero, we are testing aliases between X and Y + C.
XSIZE is the size in bytes of the X reference,
similarly YSIZE is the size in bytes for Y.
align memory references, as is done on the Alpha.
Nice to notice that varying addresses cannot conflict with fp if no
- local variables had their addresses taken, but that's too hard now. */
+ local variables had their addresses taken, but that's too hard now.
+
+ ??? Contrary to the tree alias oracle this does not return
+ one for X + non-constant and Y + non-constant when X and Y are equal.
+ If that is fixed the TBAA hack for union type-punning can be removed. */
static int
memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c)
{
if (GET_CODE (x) == VALUE)
- x = get_addr (x);
+ {
+ if (REG_P (y))
+ {
+ struct elt_loc_list *l = NULL;
+ if (CSELIB_VAL_PTR (x))
+ for (l = CSELIB_VAL_PTR (x)->locs; l; l = l->next)
+ if (REG_P (l->loc) && rtx_equal_for_memref_p (l->loc, y))
+ break;
+ if (l)
+ x = y;
+ else
+ x = get_addr (x);
+ }
+ /* Don't call get_addr if y is the same VALUE. */
+ else if (x != y)
+ x = get_addr (x);
+ }
if (GET_CODE (y) == VALUE)
- y = get_addr (y);
+ {
+ if (REG_P (x))
+ {
+ struct elt_loc_list *l = NULL;
+ if (CSELIB_VAL_PTR (y))
+ for (l = CSELIB_VAL_PTR (y)->locs; l; l = l->next)
+ if (REG_P (l->loc) && rtx_equal_for_memref_p (l->loc, x))
+ break;
+ if (l)
+ y = x;
+ else
+ y = get_addr (y);
+ }
+ /* Don't call get_addr if x is the same VALUE. */
+ else if (y != x)
+ y = get_addr (y);
+ }
if (GET_CODE (x) == HIGH)
x = XEXP (x, 0);
else if (GET_CODE (x) == LO_SUM)
else if (CONST_INT_P (y1))
return memrefs_conflict_p (xsize, x, ysize, y0, c + INTVAL (y1));
- return 1;
+ return -1;
}
else if (CONST_INT_P (x1))
return memrefs_conflict_p (xsize, x0, ysize, y, c - INTVAL (x1));
if (CONST_INT_P (y1))
return memrefs_conflict_p (xsize, x, ysize, y0, c + INTVAL (y1));
else
- return 1;
+ return -1;
}
if (GET_CODE (x) == GET_CODE (y))
rtx x1 = canon_rtx (XEXP (x, 1));
rtx y1 = canon_rtx (XEXP (y, 1));
if (! rtx_equal_for_memref_p (x1, y1))
- return 1;
+ return -1;
x0 = canon_rtx (XEXP (x, 0));
y0 = canon_rtx (XEXP (y, 0));
if (rtx_equal_for_memref_p (x0, y0))
/* Can't properly adjust our sizes. */
if (!CONST_INT_P (x1))
- return 1;
+ return -1;
xsize /= INTVAL (x1);
ysize /= INTVAL (x1);
c /= INTVAL (x1);
|| (rtx_equal_for_memref_p (x, y)
&& ((c >= 0 && xsize > c) || (c < 0 && ysize+c > 0))));
- return 1;
+ return -1;
}
- return 1;
+
+ return -1;
}
/* Functions to compute memory dependencies.
if (exprx == 0 || expry == 0)
return 0;
+ /* For spill-slot accesses make sure we have valid offsets. */
+ if ((exprx == get_spill_slot_decl (false)
+ && ! MEM_OFFSET (x))
+ || (expry == get_spill_slot_decl (false)
+ && ! MEM_OFFSET (y)))
+ return 0;
+
/* If both are field references, we may be able to determine something. */
if (TREE_CODE (exprx) == COMPONENT_REF
&& TREE_CODE (expry) == COMPONENT_REF
exprx = t;
}
}
- else if (INDIRECT_REF_P (exprx))
- {
- exprx = TREE_OPERAND (exprx, 0);
- if (flag_argument_noalias < 2
- || TREE_CODE (exprx) != PARM_DECL)
- return 0;
- }
moffsety = MEM_OFFSET (y);
if (TREE_CODE (expry) == COMPONENT_REF)
expry = t;
}
}
- else if (INDIRECT_REF_P (expry))
- {
- expry = TREE_OPERAND (expry, 0);
- if (flag_argument_noalias < 2
- || TREE_CODE (expry) != PARM_DECL)
- return 0;
- }
if (! DECL_P (exprx) || ! DECL_P (expry))
return 0;
{
rtx x_addr, mem_addr;
rtx base;
+ int ret;
if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
return 1;
|| MEM_ALIAS_SET (mem) == ALIAS_SET_MEMORY_BARRIER)
return 1;
- if (DIFFERENT_ALIAS_SETS_P (x, mem))
- return 0;
-
/* Read-only memory is by definition never modified, and therefore can't
conflict with anything. We don't expect to find read-only set on MEM,
but stupid user tricks can produce them, so don't die. */
if (MEM_READONLY_P (x))
return 0;
- if (nonoverlapping_memrefs_p (mem, x))
- return 0;
-
/* If we have MEMs refering to different address spaces (which can
potentially overlap), we cannot easily tell from the addresses
whether the references overlap. */
x_addr = canon_rtx (x_addr);
mem_addr = canon_rtx (mem_addr);
- if (! memrefs_conflict_p (GET_MODE_SIZE (mem_mode), mem_addr,
- SIZE_FOR_MODE (x), x_addr, 0))
+ if ((ret = memrefs_conflict_p (GET_MODE_SIZE (mem_mode), mem_addr,
+ SIZE_FOR_MODE (x), x_addr, 0)) != -1)
+ return ret;
+
+ if (DIFFERENT_ALIAS_SETS_P (x, mem))
+ return 0;
+
+ if (nonoverlapping_memrefs_p (mem, x))
return 0;
if (aliases_everything_p (x))
canon_true_dependence (const_rtx mem, enum machine_mode mem_mode, rtx mem_addr,
const_rtx x, rtx x_addr, bool (*varies) (const_rtx, bool))
{
+ int ret;
+
if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
return 1;
|| MEM_ALIAS_SET (mem) == ALIAS_SET_MEMORY_BARRIER)
return 1;
- if (DIFFERENT_ALIAS_SETS_P (x, mem))
- return 0;
-
/* Read-only memory is by definition never modified, and therefore can't
conflict with anything. We don't expect to find read-only set on MEM,
but stupid user tricks can produce them, so don't die. */
if (MEM_READONLY_P (x))
return 0;
- if (nonoverlapping_memrefs_p (x, mem))
- return 0;
-
/* If we have MEMs refering to different address spaces (which can
potentially overlap), we cannot easily tell from the addresses
whether the references overlap. */
return 0;
x_addr = canon_rtx (x_addr);
- if (! memrefs_conflict_p (GET_MODE_SIZE (mem_mode), mem_addr,
- SIZE_FOR_MODE (x), x_addr, 0))
+ if ((ret = memrefs_conflict_p (GET_MODE_SIZE (mem_mode), mem_addr,
+ SIZE_FOR_MODE (x), x_addr, 0)) != -1)
+ return ret;
+
+ if (DIFFERENT_ALIAS_SETS_P (x, mem))
+ return 0;
+
+ if (nonoverlapping_memrefs_p (x, mem))
return 0;
if (aliases_everything_p (x))
rtx x_addr, mem_addr;
const_rtx fixed_scalar;
rtx base;
+ int ret;
if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
return 1;
if (!writep && MEM_READONLY_P (mem))
return 0;
- if (nonoverlapping_memrefs_p (x, mem))
- return 0;
-
/* If we have MEMs refering to different address spaces (which can
potentially overlap), we cannot easily tell from the addresses
whether the references overlap. */
x_addr = canon_rtx (x_addr);
mem_addr = canon_rtx (mem_addr);
- if (!memrefs_conflict_p (SIZE_FOR_MODE (mem), mem_addr,
- SIZE_FOR_MODE (x), x_addr, 0))
+ if ((ret = memrefs_conflict_p (SIZE_FOR_MODE (mem), mem_addr,
+ SIZE_FOR_MODE (x), x_addr, 0)) != -1)
+ return ret;
+
+ if (nonoverlapping_memrefs_p (x, mem))
return 0;
fixed_scalar