#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "tree.h"
#include "tm_p.h"
#include "function.h"
#include "alias.h"
#include "emit-rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "flags.h"
#include "output.h"
#include "toplev.h"
#include "cselib.h"
#include "splay-tree.h"
#include "ggc.h"
#include "langhooks.h"
#include "timevar.h"
#include "target.h"
#include "cgraph.h"
#include "varray.h"
#include "tree-pass.h"
#include "ipa-type-escape.h"
struct alias_set_entry GTY(())
{
HOST_WIDE_INT alias_set;
splay_tree GTY((param1_is (int), param2_is (int))) children;
int has_zero_child;
};
typedef struct alias_set_entry *alias_set_entry;
static int rtx_equal_for_memref_p (rtx, rtx);
static rtx find_symbolic_term (rtx);
static int memrefs_conflict_p (int, rtx, int, rtx, HOST_WIDE_INT, int);
static void record_set (rtx, rtx, void *);
static int base_alias_check (rtx, rtx, enum machine_mode,
enum machine_mode);
static rtx find_base_value (rtx);
static int mems_in_disjoint_alias_sets_p (rtx, rtx);
static int insert_subset_children (splay_tree_node, void*);
static tree find_base_decl (tree);
static alias_set_entry get_alias_set_entry (HOST_WIDE_INT);
static rtx fixed_scalar_and_varying_struct_p (rtx, rtx, rtx, rtx,
int (*) (rtx, int));
static int aliases_everything_p (rtx);
static bool nonoverlapping_component_refs_p (tree, tree);
static tree decl_for_component_ref (tree);
static rtx adjust_offset_for_component_ref (tree, rtx);
static int nonoverlapping_memrefs_p (rtx, rtx);
static int overlapping_memrefs_p (rtx, rtx);
static int write_dependence_p (rtx, rtx, int);
static void memory_modified_1 (rtx, rtx, void *);
static void record_alias_subset (HOST_WIDE_INT, HOST_WIDE_INT);
#define SIZE_FOR_MODE(X) (GET_MODE_SIZE (GET_MODE (X)))
#define DIFFERENT_ALIAS_SETS_P(MEM1, MEM2) \
mems_in_disjoint_alias_sets_p (MEM1, MEM2)
#define MAX_ALIAS_LOOP_PASSES 10
static GTY(()) VEC(rtx,gc) *reg_base_value;
static rtx *new_reg_base_value;
static GTY((deletable)) VEC(rtx,gc) *old_reg_base_value;
static GTY (()) rtx static_reg_base_value[FIRST_PSEUDO_REGISTER];
#define REG_BASE_VALUE(X) \
(REGNO (X) < VEC_length (rtx, reg_base_value) \
? VEC_index (rtx, reg_base_value, REGNO (X)) : 0)
static GTY((length("reg_known_value_size"))) rtx *reg_known_value;
static GTY(()) unsigned int reg_known_value_size;
static bool *reg_known_equiv_p;
static bool copying_arguments;
DEF_VEC_P(alias_set_entry);
DEF_VEC_ALLOC_P(alias_set_entry,gc);
static GTY (()) VEC(alias_set_entry,gc) *alias_sets;
static inline alias_set_entry
get_alias_set_entry (HOST_WIDE_INT alias_set)
{
return VEC_index (alias_set_entry, alias_sets, alias_set);
}
static inline int
mems_in_disjoint_alias_sets_p (rtx mem1, rtx mem2)
{
gcc_assert (flag_strict_aliasing
|| (!MEM_ALIAS_SET (mem1) && !MEM_ALIAS_SET (mem2)));
return ! alias_sets_conflict_p (MEM_ALIAS_SET (mem1), MEM_ALIAS_SET (mem2));
}
static int
insert_subset_children (splay_tree_node node, void *data)
{
splay_tree_insert ((splay_tree) data, node->key, node->value);
return 0;
}
int
alias_sets_conflict_p (HOST_WIDE_INT set1, HOST_WIDE_INT set2)
{
alias_set_entry ase;
if (set1 == 0 || set2 == 0
|| set1 == set2)
return 1;
ase = get_alias_set_entry (set1);
if (ase != 0
&& (ase->has_zero_child
|| splay_tree_lookup (ase->children,
(splay_tree_key) set2)))
return 1;
ase = get_alias_set_entry (set2);
if (ase != 0
&& (ase->has_zero_child
|| splay_tree_lookup (ase->children,
(splay_tree_key) set1)))
return 1;
return 0;
}
int
alias_sets_might_conflict_p (HOST_WIDE_INT set1, HOST_WIDE_INT set2)
{
if (set1 == 0 || set2 == 0 || set1 == set2)
return 1;
return 0;
}
int
objects_must_conflict_p (tree t1, tree t2)
{
HOST_WIDE_INT set1, set2;
if (t1 == 0 && t2 == 0)
return 0;
if (t1 == t2
|| (t1 != 0 && TYPE_VOLATILE (t1) && t2 != 0 && TYPE_VOLATILE (t2)))
return 1;
set1 = t1 ? get_alias_set (t1) : 0;
set2 = t2 ? get_alias_set (t2) : 0;
return set1 == 0 || set2 == 0 || set1 == set2;
}
static tree
find_base_decl (tree t)
{
tree d0, d1;
if (t == 0 || t == error_mark_node || ! POINTER_TYPE_P (TREE_TYPE (t)))
return 0;
if (DECL_P (t))
{
if (TREE_CODE (t) == VAR_DECL && DECL_BASED_ON_RESTRICT_P (t))
t = DECL_GET_RESTRICT_BASE (t);
return t;
}
switch (TREE_CODE_CLASS (TREE_CODE (t)))
{
case tcc_unary:
return find_base_decl (TREE_OPERAND (t, 0));
case tcc_binary:
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;
default:
return 0;
}
}
bool
component_uses_parent_alias_set (tree t)
{
while (1)
{
if (!handled_component_p (t))
return false;
switch (TREE_CODE (t))
{
case COMPONENT_REF:
if (DECL_NONADDRESSABLE_P (TREE_OPERAND (t, 1)))
return true;
break;
case ARRAY_REF:
case ARRAY_RANGE_REF:
if (TYPE_NONALIASED_COMPONENT (TREE_TYPE (TREE_OPERAND (t, 0))))
return true;
break;
case REALPART_EXPR:
case IMAGPART_EXPR:
break;
default:
return true;
}
t = TREE_OPERAND (t, 0);
if (get_alias_set (TREE_TYPE (t)) == 0)
return true;
}
}
HOST_WIDE_INT
get_alias_set (tree t)
{
HOST_WIDE_INT set;
if (! flag_strict_aliasing || t == error_mark_node
|| (! TYPE_P (t)
&& (TREE_TYPE (t) == 0 || TREE_TYPE (t) == error_mark_node)))
return 0;
if (! TYPE_P (t))
{
tree inner = t;
STRIP_NOPS (t);
set = lang_hooks.get_alias_set (t);
if (set != -1)
return set;
while (handled_component_p (inner))
{
inner = TREE_OPERAND (inner, 0);
STRIP_NOPS (inner);
}
if (INDIRECT_REF_P (inner))
{
tree decl = find_base_decl (TREE_OPERAND (inner, 0));
if (decl && DECL_POINTER_ALIAS_SET_KNOWN_P (decl))
{
if (DECL_POINTER_ALIAS_SET (decl) == -2)
{
tree pointed_to_type = TREE_TYPE (TREE_TYPE (decl));
HOST_WIDE_INT pointed_to_alias_set
= get_alias_set (pointed_to_type);
if (pointed_to_alias_set == 0)
DECL_POINTER_ALIAS_SET (decl) = 0;
else if (AGGREGATE_TYPE_P (pointed_to_type))
DECL_POINTER_ALIAS_SET (decl)
= pointed_to_alias_set;
else
{
DECL_POINTER_ALIAS_SET (decl) = new_alias_set ();
record_alias_subset (pointed_to_alias_set,
DECL_POINTER_ALIAS_SET (decl));
}
}
return DECL_POINTER_ALIAS_SET (decl);
}
else if (TREE_CODE (TREE_TYPE (inner)) == VOID_TYPE
|| (TYPE_REF_CAN_ALIAS_ALL
(TREE_TYPE (TREE_OPERAND (inner, 0)))))
return 0;
}
while (component_uses_parent_alias_set (t))
{
t = TREE_OPERAND (t, 0);
STRIP_NOPS (t);
}
#ifndef ENABLE_LLVM
if (TREE_CODE (t) == VAR_DECL
&& DECL_RTL_SET_P (t) && MEM_P (DECL_RTL (t)))
return MEM_ALIAS_SET (DECL_RTL (t));
#else
if (TREE_CODE (t) == VAR_DECL
&& DECL_LLVM_SET_P (t))
return 0;
#endif
t = TREE_TYPE (t);
}
t = TYPE_MAIN_VARIANT (t);
if (TYPE_ALIAS_SET_KNOWN_P (t))
return TYPE_ALIAS_SET (t);
set = lang_hooks.get_alias_set (t);
if (set != -1)
return set;
else if (TREE_CODE (t) == FUNCTION_TYPE)
set = 0;
else if (TREE_CODE (t) == VECTOR_TYPE)
set = get_alias_set (TREE_TYPE (t));
else
set = new_alias_set ();
TYPE_ALIAS_SET (t) = set;
if (AGGREGATE_TYPE_P (t) || TREE_CODE (t) == COMPLEX_TYPE)
record_component_aliases (t);
return set;
}
HOST_WIDE_INT
new_alias_set (void)
{
if (flag_strict_aliasing)
{
if (alias_sets == 0)
VEC_safe_push (alias_set_entry, gc, alias_sets, 0);
VEC_safe_push (alias_set_entry, gc, alias_sets, 0);
return VEC_length (alias_set_entry, alias_sets) - 1;
}
else
return 0;
}
static void
record_alias_subset (HOST_WIDE_INT superset, HOST_WIDE_INT subset)
{
alias_set_entry superset_entry;
alias_set_entry subset_entry;
if (superset == subset)
return;
gcc_assert (superset);
superset_entry = get_alias_set_entry (superset);
if (superset_entry == 0)
{
superset_entry = ggc_alloc (sizeof (struct alias_set_entry));
superset_entry->alias_set = superset;
superset_entry->children
= splay_tree_new_ggc (splay_tree_compare_ints);
superset_entry->has_zero_child = 0;
VEC_replace (alias_set_entry, alias_sets, superset, superset_entry);
}
if (subset == 0)
superset_entry->has_zero_child = 1;
else
{
subset_entry = get_alias_set_entry (subset);
if (subset_entry)
{
if (subset_entry->has_zero_child)
superset_entry->has_zero_child = 1;
splay_tree_foreach (subset_entry->children, insert_subset_children,
superset_entry->children);
}
splay_tree_insert (superset_entry->children,
(splay_tree_key) subset, 0);
}
}
void
record_component_aliases (tree type)
{
HOST_WIDE_INT superset = get_alias_set (type);
tree field;
if (superset == 0)
return;
switch (TREE_CODE (type))
{
case ARRAY_TYPE:
if (! TYPE_NONALIASED_COMPONENT (type))
record_alias_subset (superset, get_alias_set (TREE_TYPE (type)));
break;
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
if (TYPE_BINFO (type))
{
int i;
tree binfo, base_binfo;
for (binfo = TYPE_BINFO (type), i = 0;
BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
record_alias_subset (superset,
get_alias_set (BINFO_TYPE (base_binfo)));
}
for (field = TYPE_FIELDS (type); field != 0; field = TREE_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL && ! DECL_NONADDRESSABLE_P (field))
record_alias_subset (superset, get_alias_set (TREE_TYPE (field)));
break;
case COMPLEX_TYPE:
record_alias_subset (superset, get_alias_set (TREE_TYPE (type)));
break;
default:
break;
}
}
static GTY(()) HOST_WIDE_INT varargs_set = -1;
HOST_WIDE_INT
get_varargs_alias_set (void)
{
#if 1
return 0;
#else
if (varargs_set == -1)
varargs_set = new_alias_set ();
return varargs_set;
#endif
}
static GTY(()) HOST_WIDE_INT frame_set = -1;
HOST_WIDE_INT
get_frame_alias_set (void)
{
if (frame_set == -1)
frame_set = new_alias_set ();
return frame_set;
}
static rtx
find_base_value (rtx src)
{
unsigned int regno;
switch (GET_CODE (src))
{
case SYMBOL_REF:
case LABEL_REF:
return src;
case REG:
regno = REGNO (src);
if (regno < FIRST_PSEUDO_REGISTER && copying_arguments)
return new_reg_base_value[regno];
if ((regno >= FIRST_PSEUDO_REGISTER || fixed_regs[regno])
&& regno < VEC_length (rtx, reg_base_value))
{
if (new_reg_base_value && new_reg_base_value[regno]
&& REG_N_SETS (regno) == 1)
return new_reg_base_value[regno];
if (VEC_index (rtx, reg_base_value, regno))
return VEC_index (rtx, reg_base_value, regno);
}
return 0;
case MEM:
if (copying_arguments
&& (XEXP (src, 0) == arg_pointer_rtx
|| (GET_CODE (XEXP (src, 0)) == PLUS
&& XEXP (XEXP (src, 0), 0) == arg_pointer_rtx)))
return gen_rtx_ADDRESS (VOIDmode, src);
return 0;
case CONST:
src = XEXP (src, 0);
if (GET_CODE (src) != PLUS && GET_CODE (src) != MINUS)
break;
case PLUS:
case MINUS:
{
rtx temp, src_0 = XEXP (src, 0), src_1 = XEXP (src, 1);
if (REG_P (src_0) && REG_POINTER (src_0))
return find_base_value (src_0);
if (REG_P (src_1) && REG_POINTER (src_1))
return find_base_value (src_1);
if (REG_P (src_0))
{
temp = find_base_value (src_0);
if (temp != 0)
src_0 = temp;
}
if (REG_P (src_1))
{
temp = find_base_value (src_1);
if (temp!= 0)
src_1 = temp;
}
if (src_0 != 0
&& (GET_CODE (src_0) == SYMBOL_REF
|| GET_CODE (src_0) == LABEL_REF
|| (GET_CODE (src_0) == ADDRESS
&& GET_MODE (src_0) != VOIDmode)))
return src_0;
if (src_1 != 0
&& (GET_CODE (src_1) == SYMBOL_REF
|| GET_CODE (src_1) == LABEL_REF
|| (GET_CODE (src_1) == ADDRESS
&& GET_MODE (src_1) != VOIDmode)))
return src_1;
if (GET_CODE (src_1) == CONST_INT || CONSTANT_P (src_0))
return find_base_value (src_0);
else if (GET_CODE (src_0) == CONST_INT || CONSTANT_P (src_1))
return find_base_value (src_1);
return 0;
}
case LO_SUM:
return find_base_value (XEXP (src, 1));
case AND:
if (GET_CODE (XEXP (src, 1)) == CONST_INT && INTVAL (XEXP (src, 1)) != 0)
return find_base_value (XEXP (src, 0));
return 0;
case TRUNCATE:
if (GET_MODE_SIZE (GET_MODE (src)) < GET_MODE_SIZE (Pmode))
break;
case HIGH:
case PRE_INC:
case PRE_DEC:
case POST_INC:
case POST_DEC:
case PRE_MODIFY:
case POST_MODIFY:
return find_base_value (XEXP (src, 0));
case ZERO_EXTEND:
case SIGN_EXTEND:
{
rtx temp = find_base_value (XEXP (src, 0));
if (temp != 0 && CONSTANT_P (temp))
temp = convert_memory_address (Pmode, temp);
return temp;
}
default:
break;
}
return 0;
}
static char *reg_seen;
static int unique_id;
static void
record_set (rtx dest, rtx set, void *data ATTRIBUTE_UNUSED)
{
unsigned regno;
rtx src;
int n;
if (!REG_P (dest))
return;
regno = REGNO (dest);
gcc_assert (regno < VEC_length (rtx, reg_base_value));
if (regno < FIRST_PSEUDO_REGISTER)
n = hard_regno_nregs[regno][GET_MODE (dest)];
else
n = 1;
if (n != 1)
{
while (--n >= 0)
{
reg_seen[regno + n] = 1;
new_reg_base_value[regno + n] = 0;
}
return;
}
if (set)
{
if (GET_CODE (set) == CLOBBER)
{
new_reg_base_value[regno] = 0;
return;
}
src = SET_SRC (set);
}
else
{
if (reg_seen[regno])
{
new_reg_base_value[regno] = 0;
return;
}
reg_seen[regno] = 1;
new_reg_base_value[regno] = gen_rtx_ADDRESS (Pmode,
GEN_INT (unique_id++));
return;
}
if (new_reg_base_value[regno] != 0
&& find_base_value (src) != new_reg_base_value[regno])
switch (GET_CODE (src))
{
case LO_SUM:
case MINUS:
if (XEXP (src, 0) != dest && XEXP (src, 1) != dest)
new_reg_base_value[regno] = 0;
break;
case PLUS:
{
rtx other = NULL_RTX;
if (XEXP (src, 0) == dest)
other = XEXP (src, 1);
else if (XEXP (src, 1) == dest)
other = XEXP (src, 0);
if (! other || find_base_value (other))
new_reg_base_value[regno] = 0;
break;
}
case AND:
if (XEXP (src, 0) != dest || GET_CODE (XEXP (src, 1)) != CONST_INT)
new_reg_base_value[regno] = 0;
break;
default:
new_reg_base_value[regno] = 0;
break;
}
else if ((regno >= FIRST_PSEUDO_REGISTER || ! fixed_regs[regno])
&& ! reg_seen[regno] && new_reg_base_value[regno] == 0)
new_reg_base_value[regno] = find_base_value (src);
reg_seen[regno] = 1;
}
void
clear_reg_alias_info (rtx reg)
{
unsigned int regno = REGNO (reg);
if (regno >= FIRST_PSEUDO_REGISTER)
{
regno -= FIRST_PSEUDO_REGISTER;
if (regno < reg_known_value_size)
{
reg_known_value[regno] = reg;
reg_known_equiv_p[regno] = false;
}
}
}
rtx
get_reg_known_value (unsigned int regno)
{
if (regno >= FIRST_PSEUDO_REGISTER)
{
regno -= FIRST_PSEUDO_REGISTER;
if (regno < reg_known_value_size)
return reg_known_value[regno];
}
return NULL;
}
static void
set_reg_known_value (unsigned int regno, rtx val)
{
if (regno >= FIRST_PSEUDO_REGISTER)
{
regno -= FIRST_PSEUDO_REGISTER;
if (regno < reg_known_value_size)
reg_known_value[regno] = val;
}
}
bool
get_reg_known_equiv_p (unsigned int regno)
{
if (regno >= FIRST_PSEUDO_REGISTER)
{
regno -= FIRST_PSEUDO_REGISTER;
if (regno < reg_known_value_size)
return reg_known_equiv_p[regno];
}
return false;
}
static void
set_reg_known_equiv_p (unsigned int regno, bool val)
{
if (regno >= FIRST_PSEUDO_REGISTER)
{
regno -= FIRST_PSEUDO_REGISTER;
if (regno < reg_known_value_size)
reg_known_equiv_p[regno] = val;
}
}
rtx
canon_rtx (rtx x)
{
if (REG_P (x) && REGNO (x) >= FIRST_PSEUDO_REGISTER)
{
rtx t = get_reg_known_value (REGNO (x));
if (t == x)
return x;
if (t)
return canon_rtx (t);
}
if (GET_CODE (x) == PLUS)
{
rtx x0 = canon_rtx (XEXP (x, 0));
rtx x1 = canon_rtx (XEXP (x, 1));
if (x0 != XEXP (x, 0) || x1 != XEXP (x, 1))
{
if (GET_CODE (x0) == CONST_INT)
return plus_constant (x1, INTVAL (x0));
else if (GET_CODE (x1) == CONST_INT)
return plus_constant (x0, INTVAL (x1));
return gen_rtx_PLUS (GET_MODE (x), x0, x1);
}
}
else if (MEM_P (x))
x = replace_equiv_address_nv (x, canon_rtx (XEXP (x, 0)));
return x;
}
static int
rtx_equal_for_memref_p (rtx x, rtx y)
{
int i;
int j;
enum rtx_code code;
const char *fmt;
if (x == 0 && y == 0)
return 1;
if (x == 0 || y == 0)
return 0;
if (x == y)
return 1;
code = GET_CODE (x);
if (code != GET_CODE (y))
return 0;
if (GET_MODE (x) != GET_MODE (y))
return 0;
switch (code)
{
case REG:
return REGNO (x) == REGNO (y);
case LABEL_REF:
return XEXP (x, 0) == XEXP (y, 0);
case SYMBOL_REF:
return XSTR (x, 0) == XSTR (y, 0);
case VALUE:
case CONST_INT:
case CONST_DOUBLE:
return 0;
default:
break;
}
if (code == PLUS)
return ((rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 0))
&& rtx_equal_for_memref_p (XEXP (x, 1), XEXP (y, 1)))
|| (rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 1))
&& rtx_equal_for_memref_p (XEXP (x, 1), XEXP (y, 0))));
if (COMMUTATIVE_P (x))
{
rtx xop0 = canon_rtx (XEXP (x, 0));
rtx yop0 = canon_rtx (XEXP (y, 0));
rtx yop1 = canon_rtx (XEXP (y, 1));
return ((rtx_equal_for_memref_p (xop0, yop0)
&& rtx_equal_for_memref_p (canon_rtx (XEXP (x, 1)), yop1))
|| (rtx_equal_for_memref_p (xop0, yop1)
&& rtx_equal_for_memref_p (canon_rtx (XEXP (x, 1)), yop0)));
}
else if (NON_COMMUTATIVE_P (x))
{
return (rtx_equal_for_memref_p (canon_rtx (XEXP (x, 0)),
canon_rtx (XEXP (y, 0)))
&& rtx_equal_for_memref_p (canon_rtx (XEXP (x, 1)),
canon_rtx (XEXP (y, 1))));
}
else if (UNARY_P (x))
return rtx_equal_for_memref_p (canon_rtx (XEXP (x, 0)),
canon_rtx (XEXP (y, 0)));
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
switch (fmt[i])
{
case 'i':
if (XINT (x, i) != XINT (y, i))
return 0;
break;
case 'E':
if (XVECLEN (x, i) != XVECLEN (y, i))
return 0;
for (j = 0; j < XVECLEN (x, i); j++)
if (rtx_equal_for_memref_p (canon_rtx (XVECEXP (x, i, j)),
canon_rtx (XVECEXP (y, i, j))) == 0)
return 0;
break;
case 'e':
if (rtx_equal_for_memref_p (canon_rtx (XEXP (x, i)),
canon_rtx (XEXP (y, i))) == 0)
return 0;
break;
case 's':
if (strcmp (XSTR (x, i), XSTR (y, i)))
return 0;
break;
case '0':
break;
default:
gcc_unreachable ();
}
}
return 1;
}
static rtx
find_symbolic_term (rtx x)
{
int i;
enum rtx_code code;
const char *fmt;
code = GET_CODE (x);
if (code == SYMBOL_REF || code == LABEL_REF)
return x;
if (OBJECT_P (x))
return 0;
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
rtx t;
if (fmt[i] == 'e')
{
t = find_symbolic_term (XEXP (x, i));
if (t != 0)
return t;
}
else if (fmt[i] == 'E')
break;
}
return 0;
}
rtx
find_base_term (rtx x)
{
cselib_val *val;
struct elt_loc_list *l;
#if defined (FIND_BASE_TERM)
x = FIND_BASE_TERM (x);
#endif
switch (GET_CODE (x))
{
case REG:
return REG_BASE_VALUE (x);
case TRUNCATE:
if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (Pmode))
return 0;
case HIGH:
case PRE_INC:
case PRE_DEC:
case POST_INC:
case POST_DEC:
case PRE_MODIFY:
case POST_MODIFY:
return find_base_term (XEXP (x, 0));
case ZERO_EXTEND:
case SIGN_EXTEND:
{
rtx temp = find_base_term (XEXP (x, 0));
if (temp != 0 && CONSTANT_P (temp))
temp = convert_memory_address (Pmode, temp);
return temp;
}
case VALUE:
val = CSELIB_VAL_PTR (x);
if (!val)
return 0;
for (l = val->locs; l; l = l->next)
if ((x = find_base_term (l->loc)) != 0)
return x;
return 0;
case CONST:
x = XEXP (x, 0);
if (GET_CODE (x) != PLUS && GET_CODE (x) != MINUS)
return 0;
case LO_SUM:
case PLUS:
case MINUS:
{
rtx tmp1 = XEXP (x, 0);
rtx tmp2 = XEXP (x, 1);
if (tmp1 == pic_offset_table_rtx && CONSTANT_P (tmp2))
return find_base_term (tmp2);
if (REG_P (tmp1) && REG_POINTER (tmp1))
return find_base_term (tmp1);
if (REG_P (tmp2) && REG_POINTER (tmp2))
return find_base_term (tmp2);
tmp1 = find_base_term (tmp1);
tmp2 = find_base_term (tmp2);
if (tmp1 != 0
&& (GET_CODE (tmp1) == SYMBOL_REF
|| GET_CODE (tmp1) == LABEL_REF
|| (GET_CODE (tmp1) == ADDRESS
&& GET_MODE (tmp1) != VOIDmode)))
return tmp1;
if (tmp2 != 0
&& (GET_CODE (tmp2) == SYMBOL_REF
|| GET_CODE (tmp2) == LABEL_REF
|| (GET_CODE (tmp2) == ADDRESS
&& GET_MODE (tmp2) != VOIDmode)))
return tmp2;
return 0;
}
case AND:
if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) != 0)
return find_base_term (XEXP (x, 0));
return 0;
case SYMBOL_REF:
case LABEL_REF:
return x;
default:
return 0;
}
}
static int
base_alias_check (rtx x, rtx y, enum machine_mode x_mode,
enum machine_mode y_mode)
{
rtx x_base = find_base_term (x);
rtx y_base = find_base_term (y);
if (x_base == 0)
{
rtx x_c;
if (! flag_expensive_optimizations || (x_c = canon_rtx (x)) == x)
return 1;
x_base = find_base_term (x_c);
if (x_base == 0)
return 1;
}
if (y_base == 0)
{
rtx y_c;
if (! flag_expensive_optimizations || (y_c = canon_rtx (y)) == y)
return 1;
y_base = find_base_term (y_c);
if (y_base == 0)
return 1;
}
if (rtx_equal_p (x_base, y_base))
return 1;
if (GET_CODE (x_base) != ADDRESS && GET_CODE (y_base) != ADDRESS)
{
if (GET_CODE (x) == AND && GET_CODE (y) == AND)
return 1;
if (GET_CODE (x) == AND
&& (GET_CODE (XEXP (x, 1)) != CONST_INT
|| (int) GET_MODE_UNIT_SIZE (y_mode) < -INTVAL (XEXP (x, 1))))
return 1;
if (GET_CODE (y) == AND
&& (GET_CODE (XEXP (y, 1)) != CONST_INT
|| (int) GET_MODE_UNIT_SIZE (x_mode) < -INTVAL (XEXP (y, 1))))
return 1;
return 0;
}
if ((GET_CODE (x_base) == ADDRESS && GET_MODE (x_base) == Pmode)
|| (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;
return ! (GET_MODE (x_base) == VOIDmode && GET_MODE (y_base) == VOIDmode);
}
rtx
get_addr (rtx x)
{
cselib_val *v;
struct elt_loc_list *l;
if (GET_CODE (x) != VALUE)
return x;
v = CSELIB_VAL_PTR (x);
if (v)
{
for (l = v->locs; l; l = l->next)
if (CONSTANT_P (l->loc))
return l->loc;
for (l = v->locs; l; l = l->next)
if (!REG_P (l->loc) && !MEM_P (l->loc))
return l->loc;
if (v->locs)
return v->locs->loc;
}
return x;
}
static rtx
addr_side_effect_eval (rtx addr, int size, int n_refs)
{
int offset = 0;
switch (GET_CODE (addr))
{
case PRE_INC:
offset = (n_refs + 1) * size;
break;
case PRE_DEC:
offset = -(n_refs + 1) * size;
break;
case POST_INC:
offset = n_refs * size;
break;
case POST_DEC:
offset = -n_refs * size;
break;
default:
return addr;
}
if (offset)
addr = gen_rtx_PLUS (GET_MODE (addr), XEXP (addr, 0),
GEN_INT (offset));
else
addr = XEXP (addr, 0);
addr = canon_rtx (addr);
return addr;
}
static int
memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c,
int memrefs_may_conflist)
{
if (GET_CODE (x) == VALUE)
x = get_addr (x);
if (GET_CODE (y) == VALUE)
y = get_addr (y);
if (GET_CODE (x) == HIGH)
x = XEXP (x, 0);
else if (GET_CODE (x) == LO_SUM)
x = XEXP (x, 1);
else
x = addr_side_effect_eval (x, xsize, 0);
if (GET_CODE (y) == HIGH)
y = XEXP (y, 0);
else if (GET_CODE (y) == LO_SUM)
y = XEXP (y, 1);
else
y = addr_side_effect_eval (y, ysize, 0);
if (rtx_equal_for_memref_p (x, y))
{
if (xsize <= 0 || ysize <= 0)
return 1;
if (c >= 0 && xsize > c)
return 1;
if (c < 0 && ysize+c > 0)
return 1;
return 0;
}
if (GET_CODE (x) == PLUS)
{
rtx x0 = XEXP (x, 0);
rtx x1 = XEXP (x, 1);
if (GET_CODE (y) == PLUS)
{
rtx y0 = XEXP (y, 0);
rtx y1 = XEXP (y, 1);
if (rtx_equal_for_memref_p (x1, y1))
return memrefs_conflict_p (xsize, x0, ysize, y0, c,
memrefs_may_conflist);
if (rtx_equal_for_memref_p (x0, y0))
return memrefs_conflict_p (xsize, x1, ysize, y1, c,
memrefs_may_conflist);
if (GET_CODE (x1) == CONST_INT)
{
if (GET_CODE (y1) == CONST_INT)
return memrefs_conflict_p (xsize, x0, ysize, y0,
c - INTVAL (x1) + INTVAL (y1),
memrefs_may_conflist);
else
return memrefs_conflict_p (xsize, x0, ysize, y,
c - INTVAL (x1),
memrefs_may_conflist);
}
else if (GET_CODE (y1) == CONST_INT)
return memrefs_conflict_p (xsize, x, ysize, y0, c + INTVAL (y1),
memrefs_may_conflist);
return memrefs_may_conflist;
}
else if (GET_CODE (x1) == CONST_INT)
return memrefs_conflict_p (xsize, x0, ysize, y, c - INTVAL (x1),
memrefs_may_conflist);
}
else if (GET_CODE (y) == PLUS)
{
rtx y0 = XEXP (y, 0);
rtx y1 = XEXP (y, 1);
if (GET_CODE (y1) == CONST_INT)
return memrefs_conflict_p (xsize, x, ysize, y0, c + INTVAL (y1),
memrefs_may_conflist);
else
return memrefs_may_conflist;
}
if (GET_CODE (x) == GET_CODE (y))
switch (GET_CODE (x))
{
case MULT:
{
rtx x0, y0;
rtx x1 = canon_rtx (XEXP (x, 1));
rtx y1 = canon_rtx (XEXP (y, 1));
if (! rtx_equal_for_memref_p (x1, y1))
return memrefs_may_conflist;
x0 = canon_rtx (XEXP (x, 0));
y0 = canon_rtx (XEXP (y, 0));
if (rtx_equal_for_memref_p (x0, y0))
return (xsize == 0 || ysize == 0
|| (c >= 0 && xsize > c) || (c < 0 && ysize+c > 0));
if (GET_CODE (x1) != CONST_INT)
return memrefs_may_conflist;
xsize /= INTVAL (x1);
ysize /= INTVAL (x1);
c /= INTVAL (x1);
return memrefs_conflict_p (xsize, x0, ysize, y0, c,
memrefs_may_conflist);
}
default:
break;
}
if (GET_CODE (x) == AND && GET_CODE (XEXP (x, 1)) == CONST_INT)
{
if (GET_CODE (y) == AND || ysize < -INTVAL (XEXP (x, 1)))
xsize = -1;
return memrefs_conflict_p (xsize, canon_rtx (XEXP (x, 0)), ysize, y, c,
memrefs_may_conflist);
}
if (GET_CODE (y) == AND && GET_CODE (XEXP (y, 1)) == CONST_INT)
{
if (GET_CODE (x) == AND || xsize < -INTVAL (XEXP (y, 1)))
ysize = -1;
return memrefs_conflict_p (xsize, x, ysize, canon_rtx (XEXP (y, 0)), c,
memrefs_may_conflist);
}
if (CONSTANT_P (x))
{
if (GET_CODE (x) == CONST_INT && GET_CODE (y) == CONST_INT)
{
c += (INTVAL (y) - INTVAL (x));
return (xsize <= 0 || ysize <= 0
|| (c >= 0 && xsize > c) || (c < 0 && ysize+c > 0));
}
if (GET_CODE (x) == CONST)
{
if (GET_CODE (y) == CONST)
return memrefs_conflict_p (xsize, canon_rtx (XEXP (x, 0)),
ysize, canon_rtx (XEXP (y, 0)), c,
memrefs_may_conflist);
else
return memrefs_conflict_p (xsize, canon_rtx (XEXP (x, 0)),
ysize, y, c,
memrefs_may_conflist);
}
if (GET_CODE (y) == CONST)
return memrefs_conflict_p (xsize, x, ysize,
canon_rtx (XEXP (y, 0)), c,
memrefs_may_conflist);
if (CONSTANT_P (y))
return (xsize <= 0 || ysize <= 0
|| (rtx_equal_for_memref_p (x, y)
&& ((c >= 0 && xsize > c) || (c < 0 && ysize+c > 0))));
return memrefs_may_conflist;
}
return memrefs_may_conflist;
}
int
read_dependence (rtx mem, rtx x)
{
return MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem);
}
static rtx
fixed_scalar_and_varying_struct_p (rtx mem1, rtx mem2, rtx mem1_addr,
rtx mem2_addr,
int (*varies_p) (rtx, int))
{
if (! flag_strict_aliasing)
return NULL_RTX;
if (MEM_SCALAR_P (mem1) && MEM_IN_STRUCT_P (mem2)
&& !varies_p (mem1_addr, 1) && varies_p (mem2_addr, 1))
return mem1;
if (MEM_IN_STRUCT_P (mem1) && MEM_SCALAR_P (mem2)
&& varies_p (mem1_addr, 1) && !varies_p (mem2_addr, 1))
return mem2;
return NULL_RTX;
}
static int
aliases_everything_p (rtx mem)
{
if (GET_CODE (XEXP (mem, 0)) == AND)
return 1;
return 0;
}
static bool
nonoverlapping_component_refs_p (tree x, tree y)
{
tree fieldx, fieldy, typex, typey, orig_y;
do
{
orig_y = y;
do
{
fieldx = TREE_OPERAND (x, 1);
typex = TYPE_MAIN_VARIANT (DECL_FIELD_CONTEXT (fieldx));
y = orig_y;
do
{
fieldy = TREE_OPERAND (y, 1);
typey = TYPE_MAIN_VARIANT (DECL_FIELD_CONTEXT (fieldy));
if (typex == typey)
goto found;
y = TREE_OPERAND (y, 0);
}
while (y && TREE_CODE (y) == COMPONENT_REF);
x = TREE_OPERAND (x, 0);
}
while (x && TREE_CODE (x) == COMPONENT_REF);
return false;
found:
if (TREE_CODE (typex) == RECORD_TYPE
&& fieldx != fieldy)
return true;
x = TREE_OPERAND (x, 0);
y = TREE_OPERAND (y, 0);
}
while (x && y
&& TREE_CODE (x) == COMPONENT_REF
&& TREE_CODE (y) == COMPONENT_REF);
return false;
}
static tree
decl_for_component_ref (tree x)
{
do
{
x = TREE_OPERAND (x, 0);
}
while (x && TREE_CODE (x) == COMPONENT_REF);
return x && DECL_P (x) ? x : NULL_TREE;
}
static rtx
adjust_offset_for_component_ref (tree x, rtx offset)
{
HOST_WIDE_INT ioffset;
if (! offset)
return NULL_RTX;
ioffset = INTVAL (offset);
do
{
tree offset = component_ref_field_offset (x);
tree field = TREE_OPERAND (x, 1);
if (! host_integerp (offset, 1))
return NULL_RTX;
ioffset += (tree_low_cst (offset, 1)
+ (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
/ BITS_PER_UNIT));
x = TREE_OPERAND (x, 0);
}
while (x && TREE_CODE (x) == COMPONENT_REF);
return GEN_INT (ioffset);
}
static int
nonoverlapping_memrefs_p (rtx x, rtx y)
{
tree exprx = MEM_EXPR (x), expry = MEM_EXPR (y);
rtx rtlx, rtly;
rtx basex, basey;
rtx moffsetx, moffsety;
HOST_WIDE_INT offsetx = 0, offsety = 0, sizex, sizey, tem;
if (exprx == 0 || expry == 0)
return 0;
if (TREE_CODE (exprx) == COMPONENT_REF
&& TREE_CODE (expry) == COMPONENT_REF
&& nonoverlapping_component_refs_p (exprx, expry))
return 1;
moffsetx = MEM_OFFSET (x);
if (TREE_CODE (exprx) == COMPONENT_REF)
{
if (TREE_CODE (expry) == VAR_DECL
&& POINTER_TYPE_P (TREE_TYPE (expry)))
{
tree field = TREE_OPERAND (exprx, 1);
tree fieldcontext = DECL_FIELD_CONTEXT (field);
if (ipa_type_escape_field_does_not_clobber_p (fieldcontext,
TREE_TYPE (field)))
return 1;
}
{
tree t = decl_for_component_ref (exprx);
if (! t)
return 0;
moffsetx = adjust_offset_for_component_ref (exprx, moffsetx);
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)
{
if (TREE_CODE (exprx) == VAR_DECL
&& POINTER_TYPE_P (TREE_TYPE (exprx)))
{
tree field = TREE_OPERAND (expry, 1);
tree fieldcontext = DECL_FIELD_CONTEXT (field);
if (ipa_type_escape_field_does_not_clobber_p (fieldcontext,
TREE_TYPE (field)))
return 1;
}
{
tree t = decl_for_component_ref (expry);
if (! t)
return 0;
moffsety = adjust_offset_for_component_ref (expry, moffsety);
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;
rtlx = DECL_RTL (exprx);
rtly = DECL_RTL (expry);
if ((!MEM_P (rtlx) || !MEM_P (rtly))
&& ! rtx_equal_p (rtlx, rtly))
return 1;
basex = MEM_P (rtlx) ? XEXP (rtlx, 0) : rtlx;
if (GET_CODE (basex) == PLUS && GET_CODE (XEXP (basex, 1)) == CONST_INT)
offsetx = INTVAL (XEXP (basex, 1)), basex = XEXP (basex, 0);
basey = MEM_P (rtly) ? XEXP (rtly, 0) : rtly;
if (GET_CODE (basey) == PLUS && GET_CODE (XEXP (basey, 1)) == CONST_INT)
offsety = INTVAL (XEXP (basey, 1)), basey = XEXP (basey, 0);
if (! rtx_equal_p (basex, basey))
return ((CONSTANT_P (basex) && CONSTANT_P (basey))
|| (CONSTANT_P (basex) && REG_P (basey)
&& REGNO_PTR_FRAME_P (REGNO (basey)))
|| (CONSTANT_P (basey) && REG_P (basex)
&& REGNO_PTR_FRAME_P (REGNO (basex))));
sizex = (!MEM_P (rtlx) ? (int) GET_MODE_SIZE (GET_MODE (rtlx))
: MEM_SIZE (rtlx) ? INTVAL (MEM_SIZE (rtlx))
: -1);
sizey = (!MEM_P (rtly) ? (int) GET_MODE_SIZE (GET_MODE (rtly))
: MEM_SIZE (rtly) ? INTVAL (MEM_SIZE (rtly)) :
-1);
if (moffsetx)
offsetx += INTVAL (moffsetx), sizex -= INTVAL (moffsetx);
if (moffsety)
offsety += INTVAL (moffsety), sizey -= INTVAL (moffsety);
if (MEM_SIZE (x) && moffsetx)
sizex = INTVAL (MEM_SIZE (x));
if (MEM_SIZE (y) && moffsety)
sizey = INTVAL (MEM_SIZE (y));
if (offsetx > offsety)
{
tem = offsetx, offsetx = offsety, offsety = tem;
tem = sizex, sizex = sizey, sizey = tem;
}
return sizex >= 0 && offsety >= offsetx + sizex;
}
static int
overlapping_trees_p (tree exprx, tree expry)
{
if (exprx == 0 || expry == 0)
return 0;
if (TREE_CODE (exprx) != TREE_CODE (expry))
return 0;
if (TREE_CODE (exprx) == COMPONENT_REF)
{
if (TREE_OPERAND (exprx, 1) != TREE_OPERAND (expry, 1))
return 0;
return overlapping_trees_p (TREE_OPERAND (exprx, 0),
TREE_OPERAND (expry, 0));
}
if (TREE_CODE (exprx) == INDIRECT_REF)
return overlapping_trees_p (TREE_OPERAND (exprx, 0),
TREE_OPERAND (expry, 0));
if (TREE_CODE (exprx) == VAR_DECL
|| TREE_CODE (exprx) == PARM_DECL
|| TREE_CODE (exprx) == CONST_DECL
|| TREE_CODE (exprx) == FUNCTION_DECL)
return exprx == expry;
return 0;
}
static int
overlapping_memrefs_p (rtx x, rtx y)
{
tree exprx = MEM_EXPR (x), expry = MEM_EXPR (y);
rtx offsetx = MEM_OFFSET (x), offsety = MEM_OFFSET (y);
if (offsetx != 0 && offsety != 0 && !rtx_equal_p (offsetx, offsety))
return 0;
return overlapping_trees_p (exprx, expry);
}
int
must_true_dependence (rtx mem, rtx x)
{
rtx x_addr, mem_addr;
enum machine_mode mem_mode;
if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
return 1;
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;
mem_mode = GET_MODE (mem);
x_addr = get_addr (XEXP (x, 0));
mem_addr = get_addr (XEXP (mem, 0));
if (overlapping_memrefs_p (mem, x))
return 1;
if (aliases_everything_p (x))
return 1;
x_addr = canon_rtx (x_addr);
mem_addr = canon_rtx (mem_addr);
if (mem_mode == QImode || GET_CODE (mem_addr) == AND)
return 1;
if (mem_mode == BLKmode || GET_MODE (x) == BLKmode)
return 1;
return memrefs_conflict_p (GET_MODE_SIZE (mem_mode), mem_addr,
SIZE_FOR_MODE (x), x_addr, 0, 0);
}
int
true_dependence (rtx mem, enum machine_mode mem_mode, rtx x,
int (*varies) (rtx, int))
{
rtx x_addr, mem_addr;
rtx base;
if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
return 1;
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;
if (DIFFERENT_ALIAS_SETS_P (x, mem))
return 0;
if (MEM_READONLY_P (x))
return 0;
if (nonoverlapping_memrefs_p (mem, x))
return 0;
if (mem_mode == VOIDmode)
mem_mode = GET_MODE (mem);
x_addr = get_addr (XEXP (x, 0));
mem_addr = get_addr (XEXP (mem, 0));
base = find_base_term (x_addr);
if (base && (GET_CODE (base) == LABEL_REF
|| (GET_CODE (base) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (base))))
return 0;
if (overlapping_memrefs_p (mem, x))
return 1;
if (! base_alias_check (x_addr, mem_addr, GET_MODE (x), mem_mode))
return 0;
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, 1))
return 0;
if (aliases_everything_p (x))
return 1;
if (mem_mode == QImode || GET_CODE (mem_addr) == AND)
return 1;
if (mem_mode == BLKmode || GET_MODE (x) == BLKmode)
return 1;
return ! fixed_scalar_and_varying_struct_p (mem, x, mem_addr, x_addr,
varies);
}
int
canon_true_dependence (rtx mem, enum machine_mode mem_mode, rtx mem_addr,
rtx x, int (*varies) (rtx, int))
{
rtx x_addr;
if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
return 1;
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;
if (DIFFERENT_ALIAS_SETS_P (x, mem))
return 0;
if (MEM_READONLY_P (x))
return 0;
if (nonoverlapping_memrefs_p (x, mem))
return 0;
x_addr = get_addr (XEXP (x, 0));
if (overlapping_memrefs_p (mem, x))
return 1;
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, 1))
return 0;
if (aliases_everything_p (x))
return 1;
if (mem_mode == QImode || GET_CODE (mem_addr) == AND)
return 1;
if (mem_mode == BLKmode || GET_MODE (x) == BLKmode)
return 1;
return ! fixed_scalar_and_varying_struct_p (mem, x, mem_addr, x_addr,
varies);
}
static int
write_dependence_p (rtx mem, rtx x, int writep)
{
rtx x_addr, mem_addr;
rtx fixed_scalar;
rtx base;
if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
return 1;
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;
x_addr = get_addr (XEXP (x, 0));
mem_addr = get_addr (XEXP (mem, 0));
if (rtx_equal_p (x_addr, mem_addr))
return 1;
if (DIFFERENT_ALIAS_SETS_P (x, mem))
return 0;
if (!writep && MEM_READONLY_P (mem))
return 0;
if (nonoverlapping_memrefs_p (x, mem))
return 0;
x_addr = get_addr (XEXP (x, 0));
mem_addr = get_addr (XEXP (mem, 0));
if (! writep)
{
base = find_base_term (mem_addr);
if (base && (GET_CODE (base) == LABEL_REF
|| (GET_CODE (base) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (base))))
return 0;
}
if (overlapping_memrefs_p (mem, x))
return 1;
if (! base_alias_check (x_addr, mem_addr, GET_MODE (x),
GET_MODE (mem)))
return 0;
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, 1))
return 0;
fixed_scalar
= fixed_scalar_and_varying_struct_p (mem, x, mem_addr, x_addr,
rtx_addr_varies_p);
return (!(fixed_scalar == mem && !aliases_everything_p (x))
&& !(fixed_scalar == x && !aliases_everything_p (mem)));
}
int
anti_dependence (rtx mem, rtx x)
{
return write_dependence_p (mem, x, 0);
}
int
output_dependence (rtx mem, rtx x)
{
return write_dependence_p (mem, x, 1);
}
void
init_alias_once (void)
{
int i;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (FUNCTION_ARG_REGNO_P (OUTGOING_REGNO (i))
&& HARD_REGNO_MODE_OK (i, Pmode))
static_reg_base_value[i]
= gen_rtx_ADDRESS (VOIDmode, gen_rtx_REG (Pmode, i));
static_reg_base_value[STACK_POINTER_REGNUM]
= gen_rtx_ADDRESS (Pmode, stack_pointer_rtx);
static_reg_base_value[ARG_POINTER_REGNUM]
= gen_rtx_ADDRESS (Pmode, arg_pointer_rtx);
static_reg_base_value[FRAME_POINTER_REGNUM]
= gen_rtx_ADDRESS (Pmode, frame_pointer_rtx);
#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
static_reg_base_value[HARD_FRAME_POINTER_REGNUM]
= gen_rtx_ADDRESS (Pmode, hard_frame_pointer_rtx);
#endif
}
static bool memory_modified;
static void
memory_modified_1 (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data)
{
if (MEM_P (x))
{
if (anti_dependence (x, (rtx)data) || output_dependence (x, (rtx)data))
memory_modified = true;
}
}
bool
memory_modified_in_insn_p (rtx mem, rtx insn)
{
if (!INSN_P (insn))
return false;
memory_modified = false;
note_stores (PATTERN (insn), memory_modified_1, mem);
return memory_modified;
}
void
init_alias_analysis (void)
{
unsigned int maxreg = max_reg_num ();
int changed, pass;
int i;
unsigned int ui;
rtx insn;
timevar_push (TV_ALIAS_ANALYSIS);
reg_known_value_size = maxreg - FIRST_PSEUDO_REGISTER;
reg_known_value = ggc_calloc (reg_known_value_size, sizeof (rtx));
reg_known_equiv_p = xcalloc (reg_known_value_size, sizeof (bool));
if (old_reg_base_value)
reg_base_value = old_reg_base_value;
if (reg_base_value)
VEC_truncate (rtx, reg_base_value, 0);
VEC_safe_grow (rtx, gc, reg_base_value, maxreg);
memset (VEC_address (rtx, reg_base_value), 0,
sizeof (rtx) * VEC_length (rtx, reg_base_value));
new_reg_base_value = XNEWVEC (rtx, maxreg);
reg_seen = XNEWVEC (char, maxreg);
pass = 0;
do
{
changed = 0;
unique_id = 0;
copying_arguments = true;
memset (new_reg_base_value, 0, maxreg * sizeof (rtx));
memset (reg_seen, 0, maxreg);
memcpy (new_reg_base_value, static_reg_base_value,
FIRST_PSEUDO_REGISTER * sizeof (rtx));
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
if (INSN_P (insn))
{
rtx note, set;
#if defined (HAVE_prologue) || defined (HAVE_epilogue)
if (reload_completed
&& prologue_epilogue_contains (insn))
continue;
#endif
if (GET_CODE (PATTERN (insn)) == SET
&& REG_NOTES (insn) != 0
&& find_reg_note (insn, REG_NOALIAS, NULL_RTX))
record_set (SET_DEST (PATTERN (insn)), NULL_RTX, NULL);
else
note_stores (PATTERN (insn), record_set, NULL);
set = single_set (insn);
if (set != 0
&& REG_P (SET_DEST (set))
&& REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER)
{
unsigned int regno = REGNO (SET_DEST (set));
rtx src = SET_SRC (set);
rtx t;
if (REG_NOTES (insn) != 0
&& (((note = find_reg_note (insn, REG_EQUAL, 0)) != 0
&& REG_N_SETS (regno) == 1)
|| (note = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != 0)
&& GET_CODE (XEXP (note, 0)) != EXPR_LIST
&& ! rtx_varies_p (XEXP (note, 0), 1)
&& ! reg_overlap_mentioned_p (SET_DEST (set),
XEXP (note, 0)))
{
set_reg_known_value (regno, XEXP (note, 0));
set_reg_known_equiv_p (regno,
REG_NOTE_KIND (note) == REG_EQUIV);
}
else if (REG_N_SETS (regno) == 1
&& GET_CODE (src) == PLUS
&& REG_P (XEXP (src, 0))
&& (t = get_reg_known_value (REGNO (XEXP (src, 0))))
&& GET_CODE (XEXP (src, 1)) == CONST_INT)
{
t = plus_constant (t, INTVAL (XEXP (src, 1)));
set_reg_known_value (regno, t);
set_reg_known_equiv_p (regno, 0);
}
else if (REG_N_SETS (regno) == 1
&& ! rtx_varies_p (src, 1))
{
set_reg_known_value (regno, src);
set_reg_known_equiv_p (regno, 0);
}
}
}
else if (NOTE_P (insn)
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
copying_arguments = false;
}
gcc_assert (maxreg == (unsigned int) max_reg_num());
for (ui = 0; ui < maxreg; ui++)
{
if (new_reg_base_value[ui]
&& new_reg_base_value[ui] != VEC_index (rtx, reg_base_value, ui)
&& ! rtx_equal_p (new_reg_base_value[ui],
VEC_index (rtx, reg_base_value, ui)))
{
VEC_replace (rtx, reg_base_value, ui, new_reg_base_value[ui]);
changed = 1;
}
}
}
while (changed && ++pass < MAX_ALIAS_LOOP_PASSES);
for (i = 0; i < (int)reg_known_value_size; i++)
if (reg_known_value[i] == 0)
reg_known_value[i] = regno_reg_rtx[i + FIRST_PSEUDO_REGISTER];
pass = 0;
do
{
changed = 0;
pass++;
for (ui = 0; ui < maxreg; ui++)
{
rtx base = VEC_index (rtx, reg_base_value, ui);
if (base && REG_P (base))
{
unsigned int base_regno = REGNO (base);
if (base_regno == ui)
VEC_replace (rtx, reg_base_value, ui, 0);
else
VEC_replace (rtx, reg_base_value, ui,
VEC_index (rtx, reg_base_value, base_regno));
changed = 1;
}
}
}
while (changed && pass < MAX_ALIAS_LOOP_PASSES);
free (new_reg_base_value);
new_reg_base_value = 0;
free (reg_seen);
reg_seen = 0;
timevar_pop (TV_ALIAS_ANALYSIS);
}
void
end_alias_analysis (void)
{
old_reg_base_value = reg_base_value;
ggc_free (reg_known_value);
reg_known_value = 0;
reg_known_value_size = 0;
free (reg_known_equiv_p);
reg_known_equiv_p = 0;
}
#include "gt-alias.h"