diff options
Diffstat (limited to 'gcc/alias.c')
-rw-r--r-- | gcc/alias.c | 199 |
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 |