#include "cselib.h"
#include "splay-tree.h"
#include "ggc.h"
+#include "langhooks.h"
/* The alias sets assigned to MEMs assist the back-end in determining
which MEMs can alias which other MEMs. In general, two MEMs in
static int base_alias_check PARAMS ((rtx, rtx, enum machine_mode,
enum machine_mode));
static int handled_component_p PARAMS ((tree));
-static int can_address_p PARAMS ((tree));
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 tree find_base_decl PARAMS ((tree));
+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)));
/* 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. */
+ NULL_TREE is returned. */
static tree
find_base_decl (t)
/* Return 1 if all the nested component references handled by
get_inner_reference in T are such that we can address the object in T. */
-static int
+int
can_address_p (t)
tree t;
{
else if (TREE_CODE (t) == BIT_FIELD_REF)
return 0;
+ /* Fields are addressable unless they are marked as nonaddressable or
+ the containing type has alias set 0. */
else if (TREE_CODE (t) == COMPONENT_REF
&& ! DECL_NONADDRESSABLE_P (TREE_OPERAND (t, 1))
+ && get_alias_set (TREE_TYPE (TREE_OPERAND (t, 0))) != 0
&& can_address_p (TREE_OPERAND (t, 0)))
return 1;
+ /* Likewise for arrays. */
else if ((TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
&& ! TYPE_NONALIASED_COMPONENT (TREE_TYPE (TREE_OPERAND (t, 0)))
+ && get_alias_set (TREE_TYPE (TREE_OPERAND (t, 0))) != 0
&& can_address_p (TREE_OPERAND (t, 0)))
return 1;
get_alias_set (t)
tree t;
{
- tree orig_t;
HOST_WIDE_INT set;
/* If we're not doing any alias analysis, just assume everything
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. First handle things that
- aren't types and start by removing nops since we care only about the
- actual object. Also replace PLACEHOLDER_EXPRs and pick up the outermost
- object that we could have a pointer to. */
+ aren't types. */
if (! TYPE_P (t))
{
- /* Remove any NOPs and see what any PLACEHOLD_EXPRs will expand to. */
- while (((TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR)
- && (TYPE_MODE (TREE_TYPE (t))
- == TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 0)))))
- || TREE_CODE (t) == NON_LVALUE_EXPR
- || TREE_CODE (t) == PLACEHOLDER_EXPR
- || (handled_component_p (t) && ! can_address_p (t)))
- {
- /* Give the language a chance to do something with this tree
- before we go inside it. */
- if ((set = lang_get_alias_set (t)) != -1)
- return set;
+ tree inner = t;
+ tree placeholder_ptr = 0;
+
+ /* Remove any nops, then give the language a chance to do
+ something with this tree before we look at it. */
+ STRIP_NOPS (t);
+ set = (*lang_hooks.get_alias_set) (t);
+ if (set != -1)
+ return set;
- if (TREE_CODE (t) == PLACEHOLDER_EXPR)
- t = find_placeholder (t, 0);
+ /* First see if the actual object referenced is an INDIRECT_REF from a
+ restrict-qualified pointer or a "void *". Replace
+ PLACEHOLDER_EXPRs. */
+ while (TREE_CODE (inner) == PLACEHOLDER_EXPR
+ || handled_component_p (inner))
+ {
+ if (TREE_CODE (inner) == PLACEHOLDER_EXPR)
+ inner = find_placeholder (inner, &placeholder_ptr);
else
- t = TREE_OPERAND (t, 0);
- }
+ inner = TREE_OPERAND (inner, 0);
- /* Now give the language a chance to do something but record what we
- gave it this time. */
- orig_t = t;
- if ((set = lang_get_alias_set (t)) != -1)
- return set;
+ STRIP_NOPS (inner);
+ }
/* Check for accesses through restrict-qualified pointers. */
- if (TREE_CODE (t) == INDIRECT_REF)
+ if (TREE_CODE (inner) == INDIRECT_REF)
{
- tree decl = find_base_decl (TREE_OPERAND (t, 0));
+ tree decl = find_base_decl (TREE_OPERAND (inner, 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 haven't computed the actual alias set, do it now. */
+ if (DECL_POINTER_ALIAS_SET (decl) == -2)
+ {
+ /* No two restricted pointers can point at the same thing.
+ However, a restricted pointer can point at the same thing
+ as an unrestricted pointer, if that unrestricted pointer
+ is based on the restricted pointer. So, we make the
+ alias set for the restricted pointer a subset of the
+ alias set for the type pointed to by the type of the
+ decl. */
+ HOST_WIDE_INT pointed_to_alias_set
+ = get_alias_set (TREE_TYPE (TREE_TYPE (decl)));
+
+ if (pointed_to_alias_set == 0)
+ /* It's not legal to make a subset of alias set zero. */
+ ;
+ else
+ {
+ DECL_POINTER_ALIAS_SET (decl) = new_alias_set ();
+ record_alias_subset (pointed_to_alias_set,
+ DECL_POINTER_ALIAS_SET (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)
+ else if (TREE_CODE (TREE_TYPE (inner)) == VOID_TYPE)
return 0;
}
- /* If we've already determined the alias set for this decl, just
- return it. This is necessary for C++ anonymous unions, whose
- component variables don't look like union members (boo!). */
+ /* Otherwise, pick up the outermost object that we could have a pointer
+ to, processing conversion and PLACEHOLDER_EXPR as above. */
+ placeholder_ptr = 0;
+ while (TREE_CODE (t) == PLACEHOLDER_EXPR
+ || (handled_component_p (t) && ! can_address_p (t)))
+ {
+ if (TREE_CODE (t) == PLACEHOLDER_EXPR)
+ t = find_placeholder (t, &placeholder_ptr);
+ else
+ t = TREE_OPERAND (t, 0);
+
+ STRIP_NOPS (t);
+ }
+
+ /* If we've already determined the alias set for a decl, just return
+ it. This is necessary for C++ anonymous unions, whose component
+ variables don't look like union members (boo!). */
if (TREE_CODE (t) == VAR_DECL
&& DECL_RTL_SET_P (t) && GET_CODE (DECL_RTL (t)) == MEM)
return MEM_ALIAS_SET (DECL_RTL (t));
- /* Give the language another chance to do something special. */
- if (orig_t != t
- && (set = lang_get_alias_set (t)) != -1)
- return set;
-
/* Now all we care about is the type. */
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))
+ if (TYPE_ALIAS_SET_KNOWN_P (t))
return TYPE_ALIAS_SET (t);
/* See if the language has special handling for this type. */
- if ((set = lang_get_alias_set (t)) != -1)
- {
- /* If the alias set is now known, we are done. */
- if (TYPE_ALIAS_SET_KNOWN_P (t))
- return TYPE_ALIAS_SET (t);
- }
+ set = (*lang_hooks.get_alias_set) (t);
+ if (set != -1)
+ return set;
/* 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
rtx tmp1 = XEXP (x, 0);
rtx tmp2 = XEXP (x, 1);
- /* This is a litle bit tricky since we have to determine which of
+ /* This is a little bit tricky since we have to determine which of
the two operands represents the real base address. Otherwise this
routine may return the index register instead of the base register.
if (aliases_everything_p (x))
return 1;
- /* We cannot use aliases_everyting_p to test MEM, since we must look
+ /* We cannot use aliases_everything_p to test MEM, since we must look
at MEM_MODE, rather than GET_MODE (MEM). */
if (mem_mode == QImode || GET_CODE (mem_addr) == AND)
return 1;
}
/* Canonical true dependence: X is read after store in MEM takes place.
- Variant of true_dependece which assumes MEM has already been
+ Variant of true_dependence which assumes MEM has already been
canonicalized (hence we no longer do that here).
The mem_addr argument has been added, since true_dependence computed
this value prior to canonicalizing. */
if (aliases_everything_p (x))
return 1;
- /* We cannot use aliases_everyting_p to test MEM, since we must look
+ /* We cannot use aliases_everything_p to test MEM, since we must look
at MEM_MODE, rather than GET_MODE (MEM). */
if (mem_mode == QImode || GET_CODE (mem_addr) == AND)
return 1;
start counting from zero each iteration of the loop. */
unique_id = 0;
- /* We're at the start of the funtion each iteration through the
+ /* We're at the start of the function each iteration through the
loop, so we're copying arguments. */
copying_arguments = 1;
rtx note, set;
#if defined (HAVE_prologue) || defined (HAVE_epilogue)
- /* The prologue/epilouge insns are not threaded onto the
+ /* The prologue/epilogue insns are not threaded onto the
insn chain until after reload has completed. Thus,
there is no sense wasting time checking if INSN is in
the prologue/epilogue until after reload has completed. */