X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Falias.c;h=1d69d9da603b75795ac497c8d33147e5b22c3ffe;hb=a858fcb70e3a0e58282e435098fd34b169199bbc;hp=eaa127ec8e5f8eae1e733d24d25c790c568189ad;hpb=dfe8e806805d4f3b1b396b195f7ecfba089b9b1a;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/alias.c b/gcc/alias.c index eaa127ec8e5..1d69d9da603 100644 --- a/gcc/alias.c +++ b/gcc/alias.c @@ -1,6 +1,6 @@ /* 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. @@ -42,7 +42,6 @@ along with GCC; see the file COPYING3. If not see #include "timevar.h" #include "target.h" #include "cgraph.h" -#include "varray.h" #include "tree-pass.h" #include "ipa-type-escape.h" #include "df.h" @@ -273,17 +272,17 @@ ao_ref_from_mem (ao_ref *ref, const_rtx mem) 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. */ @@ -302,33 +301,44 @@ ao_ref_from_mem (ao_ref *ref, const_rtx mem) ref->ref_alias_set = MEM_ALIAS_SET (mem); - /* For NULL MEM_OFFSET the MEM_EXPR may have been stripped arbitrarily - without recording offset or extent adjustments properly. */ - if (MEM_OFFSET (mem) == NULL_RTX) + /* 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->max_size = -1; - } - else - { - ref->offset += INTVAL (MEM_OFFSET (mem)) * BITS_PER_UNIT; - } - - /* NULL MEM_SIZE should not really happen with a non-NULL MEM_EXPR, - but just play safe here. The size may have been adjusted together - with the offset, so we need to take it if it is set and not rely - on MEM_EXPR here (which has the size determining parts potentially - stripped anyway). We lose precision for max_size which is only - available from the remaining MEM_EXPR. */ - if (MEM_SIZE (mem) == NULL_RTX) - { ref->size = -1; ref->max_size = -1; + return true; } - else - { - ref->size = INTVAL (MEM_SIZE (mem)) * BITS_PER_UNIT; - } + + /* 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. */ + if (INTVAL (MEM_OFFSET (mem)) < 0 + && ((INTVAL (MEM_SIZE (mem)) + INTVAL (MEM_OFFSET (mem))) + * BITS_PER_UNIT) == ref->size) + return true; + + ref->offset += INTVAL (MEM_OFFSET (mem)) * BITS_PER_UNIT; + ref->size = INTVAL (MEM_SIZE (mem)) * BITS_PER_UNIT; + + /* The MEM may extend into adjacent fields, so adjust max_size if + necessary. */ + if (ref->max_size != -1 + && ref->size > ref->max_size) + ref->max_size = ref->size; + + /* If MEM_OFFSET and MEM_SIZE get us outside of the base object of + the MEM_EXPR punt. This happens for STRICT_ALIGNMENT targets a lot. */ + if (MEM_EXPR (mem) != get_spill_slot_decl (false) + && (ref->offset < 0 + || (DECL_P (ref->base) + && (!host_integerp (DECL_SIZE (ref->base), 1) + || (TREE_INT_CST_LOW (DECL_SIZE ((ref->base))) + < (unsigned HOST_WIDE_INT)(ref->offset + ref->size)))))) + return false; return true; } @@ -402,7 +412,7 @@ alias_set_subset_of (alias_set_type set1, alias_set_type set2) /* 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; @@ -448,8 +458,8 @@ walk_mems_2 (rtx *x, rtx mem) { if (alias_sets_conflict_p (MEM_ALIAS_SET(*x), MEM_ALIAS_SET(mem))) return 1; - - return -1; + + return -1; } return 0; } @@ -463,7 +473,7 @@ walk_mems_1 (rtx *x, rtx *pat) if (for_each_rtx (pat, (rtx_function) walk_mems_2, *x)) /* Indicate that dependence was determined and stop traversal. */ return 1; - + return -1; } return 0; @@ -636,7 +646,7 @@ get_alias_set (tree t) aren't types. */ if (! TYPE_P (t)) { - tree inner = t; + tree inner; /* Remove any nops, then give the language a chance to do something with this tree before we look at it. */ @@ -645,8 +655,13 @@ get_alias_set (tree t) if (set != -1) return set; + /* Retrieve the original memory reference if needed. */ + 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 *". */ + inner = t; while (handled_component_p (inner)) { inner = TREE_OPERAND (inner, 0); @@ -687,7 +702,14 @@ get_alias_set (tree t) requires structural comparisons to identify compatible types use alias set zero. */ if (TYPE_STRUCTURAL_EQUALITY_P (t)) - return 0; + { + /* Allow the language to specify another alias set for this + type. */ + set = lang_hooks.get_alias_set (t); + if (set != -1) + return set; + return 0; + } t = TYPE_CANONICAL (t); /* Canonical types shouldn't form a tree nor should the canonical type require structural equality checks. */ @@ -1049,6 +1071,11 @@ find_base_value (rtx src) return 0; case TRUNCATE: + /* As we do not know which address space the pointer is refering to, we can + handle this only if the target does not support different pointer or + address modes depending on the address space. */ + if (!target_default_pointer_address_modes_p ()) + break; if (GET_MODE_SIZE (GET_MODE (src)) < GET_MODE_SIZE (Pmode)) break; /* Fall through. */ @@ -1063,6 +1090,12 @@ find_base_value (rtx src) case ZERO_EXTEND: case SIGN_EXTEND: /* used for NT/Alpha pointers */ + /* As we do not know which address space the pointer is refering to, we can + handle this only if the target does not support different pointer or + address modes depending on the address space. */ + if (!target_default_pointer_address_modes_p ()) + break; + { rtx temp = find_base_value (XEXP (src, 0)); @@ -1455,6 +1488,11 @@ find_base_term (rtx x) return REG_BASE_VALUE (x); case TRUNCATE: + /* As we do not know which address space the pointer is refering to, we can + handle this only if the target does not support different pointer or + address modes depending on the address space. */ + if (!target_default_pointer_address_modes_p ()) + return 0; if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (Pmode)) return 0; /* Fall through. */ @@ -1469,6 +1507,12 @@ find_base_term (rtx x) case ZERO_EXTEND: case SIGN_EXTEND: /* Used for Alpha/NT pointers */ + /* As we do not know which address space the pointer is refering to, we can + handle this only if the target does not support different pointer or + address modes depending on the address space. */ + if (!target_default_pointer_address_modes_p ()) + return 0; + { rtx temp = find_base_term (XEXP (x, 0)); @@ -1646,14 +1690,7 @@ base_alias_check (rtx x, rtx y, enum machine_mode x_mode, || (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 @@ -1721,8 +1758,12 @@ addr_side_effect_eval (rtx addr, int size, int n_refs) 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. @@ -1737,15 +1778,51 @@ addr_side_effect_eval (rtx addr, int size, int n_refs) 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) @@ -1803,7 +1880,7 @@ memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c) 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)); @@ -1818,7 +1895,7 @@ memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c) 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)) @@ -1833,7 +1910,7 @@ memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c) 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)) @@ -1842,7 +1919,7 @@ memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c) /* Can't properly adjust our sizes. */ if (!CONST_INT_P (x1)) - return 1; + return -1; xsize /= INTVAL (x1); ysize /= INTVAL (x1); c /= INTVAL (x1); @@ -1901,9 +1978,10 @@ memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c) || (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. @@ -2100,6 +2178,13 @@ nonoverlapping_memrefs_p (const_rtx x, const_rtx y) 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 @@ -2128,13 +2213,6 @@ nonoverlapping_memrefs_p (const_rtx x, const_rtx y) 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) @@ -2156,17 +2234,17 @@ nonoverlapping_memrefs_p (const_rtx x, const_rtx y) 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; + /* With invalid code we can end up storing into the constant pool. + Bail out to avoid ICEing when creating RTL for this. + See gfortran.dg/lto/20091028-2_0.f90. */ + if (TREE_CODE (exprx) == CONST_DECL + || TREE_CODE (expry) == CONST_DECL) + return 1; + rtlx = DECL_RTL (exprx); rtly = DECL_RTL (expry); @@ -2177,6 +2255,13 @@ nonoverlapping_memrefs_p (const_rtx x, const_rtx y) && ! rtx_equal_p (rtlx, rtly)) return 1; + /* 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_P (rtlx) && MEM_P (rtly) + && MEM_ADDR_SPACE (rtlx) != MEM_ADDR_SPACE (rtly)) + return 0; + /* Get the base and offsets of both decls. If either is a register, we know both are and are the same, so use that as the base. The only we can avoid overlap is if we can deduce that they are nonoverlapping @@ -2242,6 +2327,7 @@ true_dependence (const_rtx mem, enum machine_mode mem_mode, const_rtx x, { rtx x_addr, mem_addr; rtx base; + int ret; if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem)) return 1; @@ -2256,23 +2342,33 @@ true_dependence (const_rtx mem, enum machine_mode mem_mode, const_rtx x, || 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. */ + if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x)) + return 1; if (mem_mode == VOIDmode) mem_mode = GET_MODE (mem); - x_addr = get_addr (XEXP (x, 0)); - mem_addr = get_addr (XEXP (mem, 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)) + || (GET_CODE (x_addr) != VALUE + && GET_CODE (mem_addr) == VALUE + && reg_mentioned_p (mem_addr, x_addr)))) + { + x_addr = get_addr (x_addr); + mem_addr = get_addr (mem_addr); + } base = find_base_term (x_addr); if (base && (GET_CODE (base) == LABEL_REF @@ -2286,8 +2382,14 @@ true_dependence (const_rtx mem, enum machine_mode mem_mode, const_rtx x, 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)) @@ -2320,6 +2422,8 @@ 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; @@ -2333,27 +2437,42 @@ canon_true_dependence (const_rtx mem, enum machine_mode mem_mode, rtx mem_addr, || 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. */ + if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x)) + return 1; if (! x_addr) - x_addr = get_addr (XEXP (x, 0)); + { + 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 (! 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)) @@ -2384,6 +2503,7 @@ write_dependence_p (const_rtx mem, const_rtx x, int writep) rtx x_addr, mem_addr; const_rtx fixed_scalar; rtx base; + int ret; if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem)) return 1; @@ -2402,11 +2522,24 @@ write_dependence_p (const_rtx mem, const_rtx x, int writep) 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. */ + if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x)) + return 1; - x_addr = get_addr (XEXP (x, 0)); - mem_addr = get_addr (XEXP (mem, 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)) + || (GET_CODE (x_addr) != VALUE + && GET_CODE (mem_addr) == VALUE + && reg_mentioned_p (mem_addr, x_addr)))) + { + x_addr = get_addr (x_addr); + mem_addr = get_addr (mem_addr); + } if (! writep) { @@ -2424,8 +2557,11 @@ write_dependence_p (const_rtx mem, const_rtx x, int writep) 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