summaryrefslogtreecommitdiff
path: root/gcc/alias.c
diff options
context:
space:
mode:
authorhjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>2010-07-23 19:37:40 +0000
committerhjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>2010-07-23 19:37:40 +0000
commit10ada81fea4490f94ba2eb5923bf5baa367a38bd (patch)
tree437dca120093cc7b1f6debf6f6b31779526c7192 /gcc/alias.c
parent95a236de8aa10bf009e9368dfd28f95a980e5570 (diff)
parent3bd7a983695352a99f7dd597725eb5b839d4b4cf (diff)
downloadgcc-ifunc.tar.gz
Merged with trunk at revision 162480.ifunc
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/ifunc@162483 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/alias.c')
-rw-r--r--gcc/alias.c199
1 files changed, 91 insertions, 108 deletions
diff --git a/gcc/alias.c b/gcc/alias.c
index 08c38bf6616..dd846f3c996 100644
--- a/gcc/alias.c
+++ b/gcc/alias.c
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3. If not see
#include "basic-block.h"
#include "flags.h"
#include "output.h"
+#include "diagnostic-core.h"
#include "toplev.h"
#include "cselib.h"
#include "splay-tree.h"
@@ -211,9 +212,8 @@ static rtx *new_reg_base_value;
array. */
static GTY((deletable)) VEC(rtx,gc) *old_reg_base_value;
-/* Static hunks of RTL used by the aliasing code; these are initialized
- once per function to avoid unnecessary RTL allocations. */
-static GTY (()) rtx static_reg_base_value[FIRST_PSEUDO_REGISTER];
+#define static_reg_base_value \
+ (this_target_rtl->x_static_reg_base_value)
#define REG_BASE_VALUE(X) \
(REGNO (X) < VEC_length (rtx, reg_base_value) \
@@ -279,7 +279,8 @@ ao_ref_from_mem (ao_ref *ref, const_rtx mem)
/* 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)
+ if ((INDIRECT_REF_P (base)
+ || TREE_CODE (base) == MEM_REF)
&& TREE_CODE (TREE_OPERAND (base, 0)) != SSA_NAME)
return false;
@@ -293,10 +294,7 @@ ao_ref_from_mem (ao_ref *ref, const_rtx mem)
void *namep;
namep = pointer_map_contains (cfun->gimple_df->decls_to_pointers, base);
if (namep)
- {
- ref->base_alias_set = get_alias_set (base);
- ref->base = build1 (INDIRECT_REF, TREE_TYPE (base), *(tree *)namep);
- }
+ ref->base = build_simple_mem_ref (*(tree *)namep);
}
ref->ref_alias_set = MEM_ALIAS_SET (mem);
@@ -648,8 +646,8 @@ get_alias_set (tree t)
{
tree inner;
- /* Remove any nops, then give the language a chance to do
- something with this tree before we look at it. */
+ /* 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)
@@ -659,21 +657,41 @@ get_alias_set (tree t)
if (TREE_CODE (t) == TARGET_MEM_REF)
t = TMR_ORIGINAL (t);
- /* First see if the actual object referenced is an INDIRECT_REF from a
- restrict-qualified pointer or a "void *". */
+ /* Get the base object of the reference. */
inner = t;
while (handled_component_p (inner))
{
+ /* If there is a VIEW_CONVERT_EXPR in the chain we cannot use
+ the type of any component references that wrap it to
+ determine the alias-set. */
+ if (TREE_CODE (inner) == VIEW_CONVERT_EXPR)
+ t = TREE_OPERAND (inner, 0);
inner = TREE_OPERAND (inner, 0);
- STRIP_NOPS (inner);
}
+ /* Handle pointer dereferences here, they can override the
+ alias-set. */
if (INDIRECT_REF_P (inner))
{
set = get_deref_alias_set_1 (TREE_OPERAND (inner, 0));
if (set != -1)
return set;
}
+ else if (TREE_CODE (inner) == MEM_REF)
+ {
+ set = get_deref_alias_set_1 (TREE_OPERAND (inner, 1));
+ if (set != -1)
+ return set;
+ }
+
+ /* If the innermost reference is a MEM_REF that has a
+ conversion embedded treat it like a VIEW_CONVERT_EXPR above,
+ using the memory access type for determining the alias-set. */
+ if (TREE_CODE (inner) == MEM_REF
+ && TYPE_MAIN_VARIANT (TREE_TYPE (inner))
+ != TYPE_MAIN_VARIANT
+ (TREE_TYPE (TREE_TYPE (TREE_OPERAND (inner, 1)))))
+ return get_deref_alias_set (TREE_OPERAND (inner, 1));
/* Otherwise, pick up the outermost object that we could have a pointer
to, processing conversions as above. */
@@ -710,10 +728,13 @@ get_alias_set (tree t)
return set;
return 0;
}
+
t = TYPE_CANONICAL (t);
+
/* Canonical types shouldn't form a tree nor should the canonical
type require structural equality checks. */
- gcc_checking_assert (!TYPE_STRUCTURAL_EQUALITY_P (t) && TYPE_CANONICAL (t) == t);
+ gcc_checking_assert (TYPE_CANONICAL (t) == t
+ && !TYPE_STRUCTURAL_EQUALITY_P (t));
/* If this is a type with a known alias set, return it. */
if (TYPE_ALIAS_SET_KNOWN_P (t))
@@ -739,8 +760,7 @@ get_alias_set (tree t)
/* 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
- || TREE_CODE (t) == METHOD_TYPE)
+ else if (TREE_CODE (t) == FUNCTION_TYPE || TREE_CODE (t) == METHOD_TYPE)
set = 0;
/* Unless the language specifies otherwise, let vector types alias
@@ -758,18 +778,17 @@ get_alias_set (tree t)
integer(kind=4)[4] the same alias set or not.
Just be pragmatic here and make sure the array and its element
type get the same alias set assigned. */
- else if (TREE_CODE (t) == ARRAY_TYPE
- && !TYPE_NONALIASED_COMPONENT (t))
+ else if (TREE_CODE (t) == ARRAY_TYPE && !TYPE_NONALIASED_COMPONENT (t))
set = get_alias_set (TREE_TYPE (t));
+ /* Otherwise make a new alias set for this type. */
else
- /* Otherwise make a new alias set for this type. */
set = new_alias_set ();
TYPE_ALIAS_SET (t) = set;
- /* If this is an aggregate type, we must record any component aliasing
- information. */
+ /* If this is an aggregate type or a complex type, we must record any
+ component aliasing information. */
if (AGGREGATE_TYPE_P (t) || TREE_CODE (t) == COMPLEX_TYPE)
record_component_aliases (t);
@@ -885,7 +904,7 @@ record_component_aliases (tree type)
record_alias_subset (superset,
get_alias_set (BINFO_TYPE (base_binfo)));
}
- for (field = TYPE_FIELDS (type); field != 0; field = TREE_CHAIN (field))
+ for (field = TYPE_FIELDS (type); field != 0; field = DECL_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL && !DECL_NONADDRESSABLE_P (field))
record_alias_subset (superset, get_alias_set (TREE_TYPE (field)));
break;
@@ -2299,16 +2318,30 @@ nonoverlapping_memrefs_p (const_rtx x, const_rtx y)
return sizex >= 0 && offsety >= offsetx + sizex;
}
-/* True dependence: X is read after store in MEM takes place. */
+/* Helper for true_dependence and canon_true_dependence.
+ Checks for true dependence: X is read after store in MEM takes place.
-int
-true_dependence (const_rtx mem, enum machine_mode mem_mode, const_rtx x,
- bool (*varies) (const_rtx, bool))
+ VARIES is the function that should be used as rtx_varies function.
+
+ If MEM_CANONICALIZED is FALSE, then X_ADDR and MEM_ADDR should be
+ NULL_RTX, and the canonical addresses of MEM and X are both computed
+ here. If MEM_CANONICALIZED, then MEM must be already canonicalized.
+
+ If X_ADDR is non-NULL, it is used in preference of XEXP (x, 0).
+
+ Returns 1 if there is a true dependence, 0 otherwise. */
+
+static int
+true_dependence_1 (const_rtx mem, enum machine_mode mem_mode, rtx mem_addr,
+ const_rtx x, rtx x_addr, bool (*varies) (const_rtx, bool),
+ bool mem_canonicalized)
{
- rtx x_addr, mem_addr;
rtx base;
int ret;
+ gcc_checking_assert (mem_canonicalized ? (mem_addr != NULL_RTX)
+ : (mem_addr == NULL_RTX && x_addr == NULL_RTX));
+
if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
return 1;
@@ -2334,11 +2367,16 @@ true_dependence (const_rtx mem, enum machine_mode mem_mode, const_rtx x,
if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x))
return 1;
- if (mem_mode == VOIDmode)
- mem_mode = GET_MODE (mem);
+ if (! mem_addr)
+ {
+ mem_addr = XEXP (mem, 0);
+ if (mem_mode == VOIDmode)
+ mem_mode = GET_MODE (mem);
+ }
+
+ if (! x_addr)
+ x_addr = XEXP (x, 0);
- x_addr = XEXP (x, 0);
- mem_addr = XEXP (mem, 0);
if (!((GET_CODE (x_addr) == VALUE
&& GET_CODE (mem_addr) != VALUE
&& reg_mentioned_p (x_addr, mem_addr))
@@ -2347,7 +2385,8 @@ true_dependence (const_rtx mem, enum machine_mode mem_mode, const_rtx x,
&& reg_mentioned_p (mem_addr, x_addr))))
{
x_addr = get_addr (x_addr);
- mem_addr = get_addr (mem_addr);
+ if (!mem_canonicalized)
+ mem_addr = get_addr (mem_addr);
}
base = find_base_term (x_addr);
@@ -2360,7 +2399,8 @@ true_dependence (const_rtx mem, enum machine_mode mem_mode, const_rtx x,
return 0;
x_addr = canon_rtx (x_addr);
- mem_addr = canon_rtx (mem_addr);
+ if (!mem_canonicalized)
+ mem_addr = canon_rtx (mem_addr);
if ((ret = memrefs_conflict_p (GET_MODE_SIZE (mem_mode), mem_addr,
SIZE_FOR_MODE (x), x_addr, 0)) != -1)
@@ -2376,11 +2416,11 @@ true_dependence (const_rtx mem, enum machine_mode mem_mode, const_rtx x,
return 1;
/* We cannot use aliases_everything_p to test MEM, since we must look
- at MEM_MODE, rather than GET_MODE (MEM). */
+ at MEM_ADDR, rather than XEXP (mem, 0). */
if (mem_mode == QImode || GET_CODE (mem_addr) == AND)
return 1;
- /* In true_dependence we also allow BLKmode to alias anything. Why
+ /* ??? In true_dependence we also allow BLKmode to alias anything. Why
don't we do this in anti_dependence and output_dependence? */
if (mem_mode == BLKmode || GET_MODE (x) == BLKmode)
return 1;
@@ -2391,87 +2431,30 @@ true_dependence (const_rtx mem, enum machine_mode mem_mode, const_rtx x,
return rtx_refs_may_alias_p (x, mem, true);
}
+/* True dependence: X is read after store in MEM takes place. */
+
+int
+true_dependence (const_rtx mem, enum machine_mode mem_mode, const_rtx x,
+ bool (*varies) (const_rtx, bool))
+{
+ return true_dependence_1 (mem, mem_mode, NULL_RTX,
+ x, NULL_RTX, varies,
+ /*mem_canonicalized=*/false);
+}
+
/* Canonical true dependence: X is read after store in MEM takes place.
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 x_addr is non-NULL, it is used in preference of XEXP (x, 0). */
+ The mem_addr argument has been added, since true_dependence_1 computed
+ this value prior to canonicalizing. */
int
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:BLK (scratch)) is a special mechanism to conflict with everything.
- This is used in epilogue deallocation functions. */
- if (GET_MODE (x) == BLKmode && GET_CODE (XEXP (x, 0)) == SCRATCH)
- return 1;
- if (GET_MODE (mem) == BLKmode && GET_CODE (XEXP (mem, 0)) == SCRATCH)
- return 1;
- if (MEM_ALIAS_SET (x) == ALIAS_SET_MEMORY_BARRIER
- || MEM_ALIAS_SET (mem) == ALIAS_SET_MEMORY_BARRIER)
- return 1;
-
- /* 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 we have MEMs refering to different address spaces (which can
- potentially overlap), we cannot easily tell from the addresses
- whether the references overlap. */
- if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x))
- return 1;
-
- if (! x_addr)
- {
- x_addr = XEXP (x, 0);
- if (!((GET_CODE (x_addr) == VALUE
- && GET_CODE (mem_addr) != VALUE
- && reg_mentioned_p (x_addr, mem_addr))
- || (GET_CODE (x_addr) != VALUE
- && GET_CODE (mem_addr) == VALUE
- && reg_mentioned_p (mem_addr, x_addr))))
- x_addr = get_addr (x_addr);
- }
-
- if (! base_alias_check (x_addr, mem_addr, GET_MODE (x), mem_mode))
- return 0;
-
- x_addr = canon_rtx (x_addr);
- 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))
- return 1;
-
- /* 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;
-
- /* In true_dependence we also allow BLKmode to alias anything. Why
- don't we do this in anti_dependence and output_dependence? */
- if (mem_mode == BLKmode || GET_MODE (x) == BLKmode)
- return 1;
-
- if (fixed_scalar_and_varying_struct_p (mem, x, mem_addr, x_addr, varies))
- return 0;
-
- return rtx_refs_may_alias_p (x, mem, true);
+ return true_dependence_1 (mem, mem_mode, mem_addr,
+ x, x_addr, varies,
+ /*mem_canonicalized=*/true);
}
/* Returns nonzero if a write to X might alias a previous read from