summaryrefslogtreecommitdiff
path: root/gcc/alias.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/alias.c')
-rw-r--r--gcc/alias.c226
1 files changed, 210 insertions, 16 deletions
diff --git a/gcc/alias.c b/gcc/alias.c
index 9d3ff8bca0e..feed5415ad8 100644
--- a/gcc/alias.c
+++ b/gcc/alias.c
@@ -57,10 +57,10 @@ Boston, MA 02111-1307, USA. */
In this situation we say the alias set for `struct S' is the
`superset' and that those for `int' and `double' are `subsets'.
- To see whether two alias sets can point to the same memory, we must go
- down the list of decendents of each and see if there is some alias set
- in common. We need not trace past immediate decendents, however, since
- we propagate all grandchildren up one level.
+ To see whether two alias sets can point to the same memory, we must
+ see if either alias set is a subset of the other. We need not trace
+ past immediate decendents, however, since we propagate all
+ grandchildren up one level.
Alias set zero is implicitly a superset of all other alias sets.
However, this is no actual entry for alias set zero. It is an
@@ -69,7 +69,7 @@ Boston, MA 02111-1307, USA. */
typedef struct alias_set_entry
{
/* The alias set number, as stored in MEM_ALIAS_SET. */
- int alias_set;
+ HOST_WIDE_INT alias_set;
/* The children of the alias set. These are not just the immediate
children, but, in fact, all decendents. So, if we have:
@@ -81,6 +81,10 @@ typedef struct alias_set_entry
splay_tree children;
} *alias_set_entry;
+/* The language-specific function for alias analysis. If NULL, the
+ language does not do any special alias analysis. */
+HOST_WIDE_INT (*lang_get_alias_set) PARAMS ((tree));
+
static int rtx_equal_for_memref_p PARAMS ((rtx, rtx));
static rtx find_symbolic_term PARAMS ((rtx));
static rtx get_addr PARAMS ((rtx));
@@ -93,9 +97,10 @@ static int base_alias_check PARAMS ((rtx, rtx, enum machine_mode,
static rtx find_base_value PARAMS ((rtx));
static int mems_in_disjoint_alias_sets_p PARAMS ((rtx, rtx));
static int insert_subset_children PARAMS ((splay_tree_node, void*));
-static alias_set_entry get_alias_set_entry PARAMS ((int));
+static tree find_base_decl PARAMS ((tree));
+static alias_set_entry get_alias_set_entry PARAMS ((HOST_WIDE_INT));
static rtx fixed_scalar_and_varying_struct_p PARAMS ((rtx, rtx, rtx, rtx,
- int (*)(rtx)));
+ int (*) (rtx)));
static int aliases_everything_p PARAMS ((rtx));
static int write_dependence_p PARAMS ((rtx, rtx, int));
static int nonlocal_reference_p PARAMS ((rtx));
@@ -140,7 +145,7 @@ static rtx *new_reg_base_value;
static unsigned int reg_base_value_size; /* size of reg_base_value array */
#define REG_BASE_VALUE(X) \
- ((unsigned) REGNO (X) < reg_base_value_size ? reg_base_value[REGNO (X)] : 0)
+ (REGNO (X) < reg_base_value_size ? reg_base_value[REGNO (X)] : 0)
/* Vector of known invariant relationships between registers. Set in
loop unrolling. Indexed by register number, if nonzero the value
@@ -187,7 +192,7 @@ static splay_tree alias_sets;
static alias_set_entry
get_alias_set_entry (alias_set)
- int alias_set;
+ HOST_WIDE_INT alias_set;
{
splay_tree_node sn
= splay_tree_lookup (alias_sets, (splay_tree_key) alias_set);
@@ -236,8 +241,7 @@ mems_in_disjoint_alias_sets_p (mem1, mem2)
if (MEM_ALIAS_SET (mem1) == MEM_ALIAS_SET (mem2))
return 0;
- /* Iterate through each of the children of the first alias set,
- comparing it with the second alias set. */
+ /* See if the first alias set is a subset of the second. */
ase = get_alias_set_entry (MEM_ALIAS_SET (mem1));
if (ase != 0 && splay_tree_lookup (ase->children,
(splay_tree_key) MEM_ALIAS_SET (mem2)))
@@ -266,6 +270,168 @@ insert_subset_children (node, data)
return 0;
}
+
+/* T is an expression with pointer type. Find the DECL on which this
+ expression is based. (For example, in `a[i]' this would be `a'.)
+ If there is no such DECL, or a unique decl cannot be determined,
+ NULL_TREE is retured. */
+
+static tree
+find_base_decl (t)
+ tree t;
+{
+ tree d0, d1, d2;
+
+ if (t == 0 || t == error_mark_node || ! POINTER_TYPE_P (TREE_TYPE (t)))
+ return 0;
+
+ /* If this is a declaration, return it. */
+ if (TREE_CODE_CLASS (TREE_CODE (t)) == 'd')
+ return t;
+
+ /* Handle general expressions. It would be nice to deal with
+ COMPONENT_REFs here. If we could tell that `a' and `b' were the
+ same, then `a->f' and `b->f' are also the same. */
+ switch (TREE_CODE_CLASS (TREE_CODE (t)))
+ {
+ case '1':
+ return find_base_decl (TREE_OPERAND (t, 0));
+
+ case '2':
+ /* Return 0 if found in neither or both are the same. */
+ d0 = find_base_decl (TREE_OPERAND (t, 0));
+ d1 = find_base_decl (TREE_OPERAND (t, 1));
+ if (d0 == d1)
+ return d0;
+ else if (d0 == 0)
+ return d1;
+ else if (d1 == 0)
+ return d0;
+ else
+ return 0;
+
+ case '3':
+ d0 = find_base_decl (TREE_OPERAND (t, 0));
+ d1 = find_base_decl (TREE_OPERAND (t, 1));
+ d0 = find_base_decl (TREE_OPERAND (t, 0));
+ d2 = find_base_decl (TREE_OPERAND (t, 2));
+
+ /* Set any nonzero values from the last, then from the first. */
+ if (d1 == 0) d1 = d2;
+ if (d0 == 0) d0 = d1;
+ if (d1 == 0) d1 = d0;
+ if (d2 == 0) d2 = d1;
+
+ /* At this point all are nonzero or all are zero. If all three are the
+ same, return it. Otherwise, return zero. */
+ return (d0 == d1 && d1 == d2) ? d0 : 0;
+
+ default:
+ return 0;
+ }
+}
+
+/* Return the alias set for T, which may be either a type or an
+ expression. Call language-specific routine for help, if needed. */
+
+HOST_WIDE_INT
+get_alias_set (t)
+ tree t;
+{
+ HOST_WIDE_INT set;
+ HOST_WIDE_INT bitsize, bitpos;
+ tree offset;
+ enum machine_mode mode;
+ int volatilep, unsignedp;
+ unsigned int alignment;
+
+ /* If we're not doing any alias analysis, just assume everything
+ aliases everything else. Also return 0 if this or its type is
+ an error. */
+ if (! flag_strict_aliasing || t == error_mark_node
+ || (! TYPE_P (t)
+ && (TREE_TYPE (t) == 0 || TREE_TYPE (t) == error_mark_node)))
+ return 0;
+
+ /* We can be passed either an expression or a type. This and the
+ language-specific routine may make mutually-recursive calls to
+ each other to figure out what to do. At each juncture, we see if
+ this is a tree that the language may need to handle specially.
+ But first remove nops since we care only about the actual object. */
+ while (TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR
+ || TREE_CODE (t) == NON_LVALUE_EXPR)
+ t = TREE_OPERAND (t, 0);
+
+ /* Now give the language a chance to do something. */
+ if (lang_get_alias_set != 0
+ && (set = (*lang_get_alias_set) (t)) != -1)
+ return set;
+
+ /* If this is a reference, go inside it and use the underlying object. */
+ if (TREE_CODE_CLASS (TREE_CODE (t)) == 'r')
+ t = get_inner_reference (t, &bitsize, &bitpos, &offset, &mode,
+ &unsignedp, &volatilep, &alignment);
+
+ if (TREE_CODE (t) == INDIRECT_REF)
+ {
+ /* Check for accesses through restrict-qualified pointers. */
+ tree decl = find_base_decl (TREE_OPERAND (t, 0));
+
+ if (decl && DECL_POINTER_ALIAS_SET_KNOWN_P (decl))
+ /* We use the alias set indicated in the declaration. */
+ return DECL_POINTER_ALIAS_SET (decl);
+
+ /* If we have an INDIRECT_REF via a void pointer, we don't know anything
+ about what that might alias. */
+ if (TREE_CODE (TREE_TYPE (t)) == VOID_TYPE)
+ return 0;
+ }
+
+ /* Give the language another chance to do something special. */
+ if (lang_get_alias_set != 0
+ && (set = (*lang_get_alias_set) (t)) != -1)
+ return set;
+
+ /* Now we are done with expressions, so get the type if this isn't
+ a type. */
+ if (! TYPE_P (t))
+ t = TREE_TYPE (t);
+
+ /* Variant qualifiers don't affect the alias set, so get the main
+ variant. If this is a type with a known alias set, return it. */
+ t = TYPE_MAIN_VARIANT (t);
+ if (TYPE_P (t) && TYPE_ALIAS_SET_KNOWN_P (t))
+ return TYPE_ALIAS_SET (t);
+
+ /* See if the language has special handling for this type. */
+ if (lang_get_alias_set != 0
+ && (set = (*lang_get_alias_set) (t)) != -1)
+ ;
+ /* There are no objects of FUNCTION_TYPE, so there's no point in
+ using up an alias set for them. (There are, of course, pointers
+ and references to functions, but that's different.) */
+ else if (TREE_CODE (t) == FUNCTION_TYPE)
+ set = 0;
+ else
+ /* Otherwise make a new alias set for this type. */
+ set = new_alias_set ();
+
+ TYPE_ALIAS_SET (t) = set;
+ return set;
+}
+
+/* Return a brand-new alias set. */
+
+HOST_WIDE_INT
+new_alias_set ()
+{
+ static HOST_WIDE_INT last_alias_set;
+
+ if (flag_strict_aliasing)
+ return ++last_alias_set;
+ else
+ return 0;
+}
/* Indicate that things in SUBSET can alias things in SUPERSET, but
not vice versa. For example, in C, a store to an `int' can alias a
@@ -278,8 +444,8 @@ insert_subset_children (node, data)
void
record_alias_subset (superset, subset)
- int superset;
- int subset;
+ HOST_WIDE_INT superset;
+ HOST_WIDE_INT subset;
{
alias_set_entry superset_entry;
alias_set_entry subset_entry;
@@ -326,8 +492,8 @@ void
record_component_aliases (type)
tree type;
{
- int superset = get_alias_set (type);
- int subset;
+ HOST_WIDE_INT superset = get_alias_set (type);
+ HOST_WIDE_INT subset;
tree field;
if (superset == 0)
@@ -336,7 +502,6 @@ record_component_aliases (type)
switch (TREE_CODE (type))
{
case ARRAY_TYPE:
- case COMPLEX_TYPE:
subset = get_alias_set (TREE_TYPE (type));
if (subset != 0)
record_alias_subset (superset, subset);
@@ -358,6 +523,34 @@ record_component_aliases (type)
}
}
+/* Allocate an alias set for use in storing and reading from the varargs
+ spill area. */
+
+HOST_WIDE_INT
+get_varargs_alias_set ()
+{
+ static HOST_WIDE_INT set = -1;
+
+ if (set == -1)
+ set = new_alias_set ();
+
+ return set;
+}
+
+/* Likewise, but used for the fixed portions of the frame, e.g., register
+ save areas. */
+
+HOST_WIDE_INT
+get_frame_alias_set ()
+{
+ static HOST_WIDE_INT set = -1;
+
+ if (set == -1)
+ set = new_alias_set ();
+
+ return set;
+}
+
/* Inside SRC, the source of a SET, find a base address. */
static rtx
@@ -975,6 +1168,7 @@ base_alias_check (x, y, x_mode, y_mode)
/* Convert the address X into something we can use. This is done by returning
it unchanged unless it is a value; in the latter case we call cselib to get
a more useful rtx. */
+
static rtx
get_addr (x)
rtx x;