#include "config.h"
#include "system.h"
#include "rtl.h"
#include "tree.h"
#include "tm_p.h"
#include "function.h"
#include "expr.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 "target.h"
typedef struct alias_set_entry
{
HOST_WIDE_INT alias_set;
splay_tree children;
int has_zero_child;
} *alias_set_entry;
static int rtx_equal_for_memref_p PARAMS ((rtx, rtx));
static rtx find_symbolic_term PARAMS ((rtx));
rtx get_addr PARAMS ((rtx));
static int memrefs_conflict_p PARAMS ((int, rtx, int, rtx,
HOST_WIDE_INT));
static void record_set PARAMS ((rtx, rtx, void *));
static rtx find_base_term PARAMS ((rtx));
static int base_alias_check PARAMS ((rtx, rtx, enum machine_mode,
enum machine_mode));
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 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)));
static int aliases_everything_p PARAMS ((rtx));
static bool nonoverlapping_component_refs_p PARAMS ((tree, tree));
static tree decl_for_component_ref PARAMS ((tree));
static rtx adjust_offset_for_component_ref PARAMS ((tree, rtx));
static int nonoverlapping_memrefs_p PARAMS ((rtx, rtx));
static int write_dependence_p PARAMS ((rtx, rtx, int));
static int nonlocal_mentioned_p_1 PARAMS ((rtx *, void *));
static int nonlocal_mentioned_p PARAMS ((rtx));
static int nonlocal_referenced_p_1 PARAMS ((rtx *, void *));
static int nonlocal_referenced_p PARAMS ((rtx));
static int nonlocal_set_p_1 PARAMS ((rtx *, void *));
static int nonlocal_set_p PARAMS ((rtx));
#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((length ("reg_base_value_size"))) rtx *reg_base_value;
static rtx *new_reg_base_value;
static unsigned int reg_base_value_size;
static GTY (()) rtx static_reg_base_value[FIRST_PSEUDO_REGISTER];
#define REG_BASE_VALUE(X) \
(REGNO (X) < reg_base_value_size \
? reg_base_value[REGNO (X)] : 0)
static rtx *alias_invariant;
rtx *reg_known_value;
static unsigned int reg_known_value_size;
char *reg_known_equiv_p;
static bool copying_arguments;
static splay_tree alias_sets;
static alias_set_entry
get_alias_set_entry (alias_set)
HOST_WIDE_INT alias_set;
{
splay_tree_node sn
= splay_tree_lookup (alias_sets, (splay_tree_key) alias_set);
return sn != 0 ? ((alias_set_entry) sn->value) : 0;
}
static int
mems_in_disjoint_alias_sets_p (mem1, mem2)
rtx mem1;
rtx mem2;
{
#ifdef ENABLE_CHECKING
if (! flag_strict_aliasing
&& (MEM_ALIAS_SET (mem1) != 0 || MEM_ALIAS_SET (mem2) != 0))
abort ();
#endif
return ! alias_sets_conflict_p (MEM_ALIAS_SET (mem1), MEM_ALIAS_SET (mem2));
}
static int
insert_subset_children (node, data)
splay_tree_node node;
void *data;
{
splay_tree_insert ((splay_tree) data, node->key, node->value);
return 0;
}
int
alias_sets_conflict_p (set1, set2)
HOST_WIDE_INT set1, 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
readonly_fields_p (type)
tree type;
{
tree field;
if (TREE_CODE (type) != RECORD_TYPE && TREE_CODE (type) != UNION_TYPE
&& TREE_CODE (type) != QUAL_UNION_TYPE)
return 0;
for (field = TYPE_FIELDS (type); field != 0; field = TREE_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL
&& (TREE_READONLY (field)
|| readonly_fields_p (TREE_TYPE (field))))
return 1;
return 0;
}
int
objects_must_conflict_p (t1, t2)
tree t1, t2;
{
if (t1 == 0 && t2 == 0)
return 0;
if ((t1 != 0 && readonly_fields_p (t1))
|| (t2 != 0 && readonly_fields_p (t2))
|| (t1 != 0 && lang_hooks.honor_readonly && TYPE_READONLY (t1))
|| (t2 != 0 && lang_hooks.honor_readonly && TYPE_READONLY (t2)))
return 0;
if (t1 == t2
|| (t1 != 0 && TYPE_VOLATILE (t1) && t2 != 0 && TYPE_VOLATILE (t2)))
return 1;
if ((t1 != 0 && AGGREGATE_TYPE_P (t1))
!= (t2 != 0 && AGGREGATE_TYPE_P (t2)))
return 0;
return alias_sets_conflict_p (t1 ? get_alias_set (t1) : 0,
t2 ? get_alias_set (t2) : 0);
}
static tree
find_base_decl (t)
tree t;
{
tree d0, d1, d2;
if (t == 0 || t == error_mark_node || ! POINTER_TYPE_P (TREE_TYPE (t)))
return 0;
if (TREE_CODE_CLASS (TREE_CODE (t)) == 'd')
return t;
switch (TREE_CODE_CLASS (TREE_CODE (t)))
{
case '1':
return find_base_decl (TREE_OPERAND (t, 0));
case '2':
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;
case '3':
d0 = find_base_decl (TREE_OPERAND (t, 0));
d1 = find_base_decl (TREE_OPERAND (t, 1));
d2 = find_base_decl (TREE_OPERAND (t, 2));
if (d1 == 0) d1 = d2;
if (d0 == 0) d0 = d1;
if (d1 == 0) d1 = d0;
if (d2 == 0) d2 = d1;
return (d0 == d1 && d1 == d2) ? d0 : 0;
default:
return 0;
}
}
int
can_address_p (t)
tree t;
{
if (! handled_component_p (t))
return 1;
else if (TREE_CODE (t) == BIT_FIELD_REF)
return 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;
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;
return 0;
}
HOST_WIDE_INT
get_alias_set (t)
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;
tree placeholder_ptr = 0;
STRIP_NOPS (t);
set = (*lang_hooks.get_alias_set) (t);
if (set != -1)
return set;
while (TREE_CODE (inner) == PLACEHOLDER_EXPR
|| handled_component_p (inner))
{
if (TREE_CODE (inner) == PLACEHOLDER_EXPR)
inner = find_placeholder (inner, &placeholder_ptr);
else
inner = TREE_OPERAND (inner, 0);
STRIP_NOPS (inner);
}
if (TREE_CODE (inner) == INDIRECT_REF)
{
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)
{
HOST_WIDE_INT pointed_to_alias_set
= get_alias_set (TREE_TYPE (TREE_TYPE (decl)));
if (pointed_to_alias_set == 0)
;
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)
return 0;
}
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 (TREE_CODE (t) == VAR_DECL
&& DECL_RTL_SET_P (t) && GET_CODE (DECL_RTL (t)) == MEM)
return MEM_ALIAS_SET (DECL_RTL (t));
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 ()
{
static HOST_WIDE_INT last_alias_set;
if (flag_strict_aliasing)
return ++last_alias_set;
else
return 0;
}
void
record_alias_subset (superset, subset)
HOST_WIDE_INT superset;
HOST_WIDE_INT subset;
{
alias_set_entry superset_entry;
alias_set_entry subset_entry;
if (superset == subset)
return;
if (superset == 0)
abort ();
superset_entry = get_alias_set_entry (superset);
if (superset_entry == 0)
{
superset_entry
= (alias_set_entry) xmalloc (sizeof (struct alias_set_entry));
superset_entry->alias_set = superset;
superset_entry->children
= splay_tree_new (splay_tree_compare_ints, 0, 0);
superset_entry->has_zero_child = 0;
splay_tree_insert (alias_sets, (splay_tree_key) superset,
(splay_tree_value) 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 (type)
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) != NULL && TYPE_BINFO_BASETYPES (type) != NULL)
{
int i;
for (i = 0; i < TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (type)); i++)
{
tree binfo = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), i);
record_alias_subset (superset,
get_alias_set (BINFO_TYPE (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;
}
}
HOST_WIDE_INT
get_varargs_alias_set ()
{
static HOST_WIDE_INT set = -1;
if (set == -1)
set = new_alias_set ();
return set;
}
HOST_WIDE_INT
get_frame_alias_set ()
{
static HOST_WIDE_INT set = -1;
if (set == -1)
set = new_alias_set ();
return set;
}
static rtx
find_base_value (src)
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 < reg_base_value_size)
{
if (new_reg_base_value && new_reg_base_value[regno]
&& REG_N_SETS (regno) == 1)
return new_reg_base_value[regno];
if (reg_base_value[regno])
return reg_base_value[regno];
}
return src;
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));
#ifdef POINTERS_EXTEND_UNSIGNED
if (temp != 0 && CONSTANT_P (temp) && GET_MODE (temp) != Pmode)
temp = convert_memory_address (Pmode, temp);
#endif
return temp;
}
default:
break;
}
return 0;
}
static char *reg_seen;
static int unique_id;
static void
record_set (dest, set, data)
rtx dest, set;
void *data ATTRIBUTE_UNUSED;
{
unsigned regno;
rtx src;
if (GET_CODE (dest) != REG)
return;
regno = REGNO (dest);
if (regno >= reg_base_value_size)
abort ();
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])
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
record_base_value (regno, val, invariant)
unsigned int regno;
rtx val;
int invariant;
{
if (regno >= reg_base_value_size)
return;
if (invariant && alias_invariant)
alias_invariant[regno] = val;
if (GET_CODE (val) == REG)
{
if (REGNO (val) < reg_base_value_size)
reg_base_value[regno] = reg_base_value[REGNO (val)];
return;
}
reg_base_value[regno] = find_base_value (val);
}
void
clear_reg_alias_info (reg)
rtx reg;
{
unsigned int regno = REGNO (reg);
if (regno < reg_known_value_size && regno >= FIRST_PSEUDO_REGISTER)
reg_known_value[regno] = reg;
}
rtx
canon_rtx (x)
rtx x;
{
if (GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER
&& REGNO (x) < reg_known_value_size)
return reg_known_value[REGNO (x)] == x
? x : canon_rtx (reg_known_value[REGNO (x)]);
else 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 (GET_CODE (x) == MEM)
x = replace_equiv_address_nv (x, canon_rtx (XEXP (x, 0)));
return x;
}
static int
rtx_equal_for_memref_p (x, y)
rtx x, 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;
x = canon_rtx (x);
y = canon_rtx (y);
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 VALUE:
return CSELIB_VAL_PTR (x) == CSELIB_VAL_PTR (y);
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 CONST_INT:
case CONST_DOUBLE:
return 0;
case ADDRESSOF:
return (XINT (x, 1) == XINT (y, 1)
&& rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 0)));
default:
break;
}
if (code == EQ || code == NE || GET_RTX_CLASS (code) == 'c')
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))));
else if (GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == '2')
return (rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 0))
&& rtx_equal_for_memref_p (XEXP (x, 1), XEXP (y, 1)));
else if (GET_RTX_CLASS (code) == '1')
return rtx_equal_for_memref_p (XEXP (x, 0), 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 (XVECEXP (x, i, j),
XVECEXP (y, i, j)) == 0)
return 0;
break;
case 'e':
if (rtx_equal_for_memref_p (XEXP (x, i), XEXP (y, i)) == 0)
return 0;
break;
case 's':
if (strcmp (XSTR (x, i), XSTR (y, i)))
return 0;
break;
case '0':
break;
default:
abort ();
}
}
return 1;
}
static rtx
find_symbolic_term (x)
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 (GET_RTX_CLASS (code) == 'o')
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;
}
static rtx
find_base_term (x)
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));
#ifdef POINTERS_EXTEND_UNSIGNED
if (temp != 0 && CONSTANT_P (temp) && GET_MODE (temp) != Pmode)
temp = convert_memory_address (Pmode, temp);
#endif
return temp;
}
case VALUE:
val = CSELIB_VAL_PTR (x);
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;
case ADDRESSOF:
return REG_BASE_VALUE (frame_pointer_rtx);
default:
return 0;
}
}
static int
base_alias_check (x, y, x_mode, y_mode)
rtx x, y;
enum machine_mode x_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 (x)
rtx x;
{
cselib_val *v;
struct elt_loc_list *l;
if (GET_CODE (x) != VALUE)
return x;
v = CSELIB_VAL_PTR (x);
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 (GET_CODE (l->loc) != REG && GET_CODE (l->loc) != MEM)
return l->loc;
if (v->locs)
return v->locs->loc;
return x;
}
rtx
addr_side_effect_eval (addr, size, n_refs)
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);
return addr;
}
static int
memrefs_conflict_p (xsize, x, ysize, y, c)
rtx x, y;
int xsize, ysize;
HOST_WIDE_INT c;
{
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 = canon_rtx (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 = canon_rtx (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);
if (rtx_equal_for_memref_p (x0, y0))
return memrefs_conflict_p (xsize, x1, ysize, y1, c);
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));
else
return memrefs_conflict_p (xsize, x0, ysize, y,
c - INTVAL (x1));
}
else if (GET_CODE (y1) == CONST_INT)
return memrefs_conflict_p (xsize, x, ysize, y0, c + INTVAL (y1));
return 1;
}
else if (GET_CODE (x1) == CONST_INT)
return memrefs_conflict_p (xsize, x0, ysize, y, c - INTVAL (x1));
}
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));
else
return 1;
}
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 1;
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 1;
xsize /= INTVAL (x1);
ysize /= INTVAL (x1);
c /= INTVAL (x1);
return memrefs_conflict_p (xsize, x0, ysize, y0, c);
}
case REG:
if (alias_invariant)
{
unsigned int r_x = REGNO (x), r_y = REGNO (y);
rtx i_x, i_y;
i_x = r_x >= reg_base_value_size ? 0 : alias_invariant[r_x];
i_y = r_y >= reg_base_value_size ? 0 : alias_invariant[r_y];
if (i_x == 0 && i_y == 0)
break;
if (! memrefs_conflict_p (xsize, i_x ? i_x : x,
ysize, i_y ? i_y : y, c))
return 0;
}
break;
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, XEXP (x, 0), ysize, y, c);
}
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, XEXP (y, 0), c);
}
if (GET_CODE (x) == ADDRESSOF)
{
if (y == frame_pointer_rtx
|| GET_CODE (y) == ADDRESSOF)
return xsize <= 0 || ysize <= 0;
}
if (GET_CODE (y) == ADDRESSOF)
{
if (x == frame_pointer_rtx)
return xsize <= 0 || ysize <= 0;
}
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);
else
return memrefs_conflict_p (xsize, canon_rtx (XEXP (x, 0)),
ysize, y, c);
}
if (GET_CODE (y) == CONST)
return memrefs_conflict_p (xsize, x, ysize,
canon_rtx (XEXP (y, 0)), c);
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 1;
}
return 1;
}
int
read_dependence (mem, x)
rtx mem;
rtx x;
{
return MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem);
}
static rtx
fixed_scalar_and_varying_struct_p (mem1, mem2, mem1_addr, mem2_addr, varies_p)
rtx mem1, mem2;
rtx mem1_addr, mem2_addr;
int (*varies_p) PARAMS ((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 (mem)
rtx mem;
{
if (GET_CODE (XEXP (mem, 0)) == AND)
return 1;
return 0;
}
static bool
nonoverlapping_component_refs_p (x, y)
tree x, y;
{
tree fieldx, fieldy, typex, typey, orig_y;
do
{
orig_y = y;
do
{
fieldx = TREE_OPERAND (x, 1);
typex = DECL_FIELD_CONTEXT (fieldx);
y = orig_y;
do
{
fieldy = TREE_OPERAND (y, 1);
typey = 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 (x)
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 (x, offset)
tree x;
rtx offset;
{
HOST_WIDE_INT ioffset;
if (! offset)
return NULL_RTX;
ioffset = INTVAL (offset);
do
{
tree field = TREE_OPERAND (x, 1);
if (! host_integerp (DECL_FIELD_OFFSET (field), 1))
return NULL_RTX;
ioffset += (tree_low_cst (DECL_FIELD_OFFSET (field), 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 (x, y)
rtx x, 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)
{
tree t = decl_for_component_ref (exprx);
if (! t)
return 0;
moffsetx = adjust_offset_for_component_ref (exprx, moffsetx);
exprx = t;
}
else if (TREE_CODE (exprx) == INDIRECT_REF)
{
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)
{
tree t = decl_for_component_ref (expry);
if (! t)
return 0;
moffsety = adjust_offset_for_component_ref (expry, moffsety);
expry = t;
}
else if (TREE_CODE (expry) == INDIRECT_REF)
{
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 ((GET_CODE (rtlx) != MEM || GET_CODE (rtly) != MEM)
&& ! rtx_equal_p (rtlx, rtly))
return 1;
basex = GET_CODE (rtlx) == MEM ? 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 = GET_CODE (rtly) == MEM ? 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 = (GET_CODE (rtlx) != MEM ? (int) GET_MODE_SIZE (GET_MODE (rtlx))
: MEM_SIZE (rtlx) ? INTVAL (MEM_SIZE (rtlx))
: -1);
sizey = (GET_CODE (rtly) != MEM ? (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;
}
int
true_dependence (mem, mem_mode, x, varies)
rtx mem;
enum machine_mode mem_mode;
rtx x;
int (*varies) PARAMS ((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 (DIFFERENT_ALIAS_SETS_P (x, mem))
return 0;
if (RTX_UNCHANGING_P (x) && ! RTX_UNCHANGING_P (mem))
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 (! 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))
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 (mem, mem_mode, mem_addr, x, varies)
rtx mem, mem_addr, x;
enum machine_mode mem_mode;
int (*varies) PARAMS ((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 (DIFFERENT_ALIAS_SETS_P (x, mem))
return 0;
if (RTX_UNCHANGING_P (x) && ! RTX_UNCHANGING_P (mem))
return 0;
if (nonoverlapping_memrefs_p (x, mem))
return 0;
x_addr = get_addr (XEXP (x, 0));
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))
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 (mem, x, writep)
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;
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 (RTX_UNCHANGING_P (x) != RTX_UNCHANGING_P (mem))
return 0;
if (! writep && RTX_UNCHANGING_P (mem))
return 0;
if (nonoverlapping_memrefs_p (x, mem))
return 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 (! 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))
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 (mem, x)
rtx mem;
rtx x;
{
return write_dependence_p (mem, x, 0);
}
int
output_dependence (mem, x)
rtx mem;
rtx x;
{
return write_dependence_p (mem, x, 1);
}
static int
nonlocal_mentioned_p_1 (loc, data)
rtx *loc;
void *data ATTRIBUTE_UNUSED;
{
rtx x = *loc;
rtx base;
int regno;
if (! x)
return 0;
switch (GET_CODE (x))
{
case SUBREG:
if (GET_CODE (SUBREG_REG (x)) == REG)
{
if (REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER
&& global_regs[subreg_regno (x)])
return 1;
return 0;
}
break;
case REG:
regno = REGNO (x);
if (regno < FIRST_PSEUDO_REGISTER && global_regs[regno])
return 1;
return 0;
case SCRATCH:
case PC:
case CC0:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
case CONST:
case LABEL_REF:
return 0;
case SYMBOL_REF:
if (CONSTANT_POOL_ADDRESS_P (x))
return 0;
return 1;
case CALL:
return 1;
case MEM:
if (MEM_VOLATILE_P (x))
return 1;
base = find_base_term (XEXP (x, 0));
if (base)
{
if (GET_CODE (base) == ADDRESS
&& GET_MODE (base) == Pmode
&& (XEXP (base, 0) == stack_pointer_rtx
|| XEXP (base, 0) == arg_pointer_rtx
#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
|| XEXP (base, 0) == hard_frame_pointer_rtx
#endif
|| XEXP (base, 0) == frame_pointer_rtx))
return 0;
if (GET_CODE (base) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (base))
return 0;
}
return 1;
case UNSPEC_VOLATILE:
case ASM_INPUT:
return 1;
case ASM_OPERANDS:
if (MEM_VOLATILE_P (x))
return 1;
default:
break;
}
return 0;
}
static int
nonlocal_mentioned_p (x)
rtx x;
{
if (INSN_P (x))
{
if (GET_CODE (x) == CALL_INSN)
{
if (! CONST_OR_PURE_CALL_P (x))
return 1;
x = CALL_INSN_FUNCTION_USAGE (x);
if (x == 0)
return 0;
}
else
x = PATTERN (x);
}
return for_each_rtx (&x, nonlocal_mentioned_p_1, NULL);
}
static int
nonlocal_referenced_p_1 (loc, data)
rtx *loc;
void *data ATTRIBUTE_UNUSED;
{
rtx x = *loc;
if (! x)
return 0;
switch (GET_CODE (x))
{
case MEM:
case REG:
case SYMBOL_REF:
case SUBREG:
return nonlocal_mentioned_p (x);
case CALL:
return 1;
case SET:
if (nonlocal_mentioned_p (SET_SRC (x)))
return 1;
if (GET_CODE (SET_DEST (x)) == MEM)
return nonlocal_mentioned_p (XEXP (SET_DEST (x), 0));
if (GET_CODE (SET_DEST (x)) != CC0
&& GET_CODE (SET_DEST (x)) != PC
&& GET_CODE (SET_DEST (x)) != REG
&& ! (GET_CODE (SET_DEST (x)) == SUBREG
&& GET_CODE (SUBREG_REG (SET_DEST (x))) == REG
&& (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (x))))
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
== ((GET_MODE_SIZE (GET_MODE (SET_DEST (x)))
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))))
return nonlocal_mentioned_p (SET_DEST (x));
return 0;
case CLOBBER:
if (GET_CODE (XEXP (x, 0)) == MEM)
return nonlocal_mentioned_p (XEXP (XEXP (x, 0), 0));
return 0;
case USE:
return nonlocal_mentioned_p (XEXP (x, 0));
case ASM_INPUT:
case UNSPEC_VOLATILE:
return 1;
case ASM_OPERANDS:
if (MEM_VOLATILE_P (x))
return 1;
default:
break;
}
return 0;
}
static int
nonlocal_referenced_p (x)
rtx x;
{
if (INSN_P (x))
{
if (GET_CODE (x) == CALL_INSN)
{
if (! CONST_OR_PURE_CALL_P (x))
return 1;
x = CALL_INSN_FUNCTION_USAGE (x);
if (x == 0)
return 0;
}
else
x = PATTERN (x);
}
return for_each_rtx (&x, nonlocal_referenced_p_1, NULL);
}
static int
nonlocal_set_p_1 (loc, data)
rtx *loc;
void *data ATTRIBUTE_UNUSED;
{
rtx x = *loc;
if (! x)
return 0;
switch (GET_CODE (x))
{
case CALL:
return 1;
case PRE_INC:
case PRE_DEC:
case POST_INC:
case POST_DEC:
case PRE_MODIFY:
case POST_MODIFY:
return nonlocal_mentioned_p (XEXP (x, 0));
case SET:
if (nonlocal_mentioned_p (SET_DEST (x)))
return 1;
return nonlocal_set_p (SET_SRC (x));
case CLOBBER:
return nonlocal_mentioned_p (XEXP (x, 0));
case USE:
return 0;
case ASM_INPUT:
case UNSPEC_VOLATILE:
return 1;
case ASM_OPERANDS:
if (MEM_VOLATILE_P (x))
return 1;
default:
break;
}
return 0;
}
static int
nonlocal_set_p (x)
rtx x;
{
if (INSN_P (x))
{
if (GET_CODE (x) == CALL_INSN)
{
if (! CONST_OR_PURE_CALL_P (x))
return 1;
x = CALL_INSN_FUNCTION_USAGE (x);
if (x == 0)
return 0;
}
else
x = PATTERN (x);
}
return for_each_rtx (&x, nonlocal_set_p_1, NULL);
}
void
mark_constant_function ()
{
rtx insn;
int nonlocal_memory_referenced;
if (TREE_READONLY (current_function_decl)
|| DECL_IS_PURE (current_function_decl)
|| TREE_THIS_VOLATILE (current_function_decl)
|| TYPE_MODE (TREE_TYPE (current_function_decl)) == VOIDmode
|| current_function_has_nonlocal_goto
|| !(*targetm.binds_local_p) (current_function_decl))
return;
if (mark_dfs_back_edges ())
return;
nonlocal_memory_referenced = 0;
init_alias_analysis ();
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
if (! INSN_P (insn))
continue;
if (nonlocal_set_p (insn) || global_reg_mentioned_p (insn)
|| volatile_refs_p (PATTERN (insn)))
break;
if (! nonlocal_memory_referenced)
nonlocal_memory_referenced = nonlocal_referenced_p (insn);
}
end_alias_analysis ();
if (insn)
;
else if (nonlocal_memory_referenced)
DECL_IS_PURE (current_function_decl) = 1;
else
TREE_READONLY (current_function_decl) = 1;
}
void
init_alias_once ()
{
int i;
#ifndef OUTGOING_REGNO
#define OUTGOING_REGNO(N) N
#endif
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
alias_sets = splay_tree_new (splay_tree_compare_ints, 0, 0);
}
void
init_alias_analysis ()
{
int maxreg = max_reg_num ();
int changed, pass;
int i;
unsigned int ui;
rtx insn;
reg_known_value_size = maxreg;
reg_known_value
= (rtx *) xcalloc ((maxreg - FIRST_PSEUDO_REGISTER), sizeof (rtx))
- FIRST_PSEUDO_REGISTER;
reg_known_equiv_p
= (char*) xcalloc ((maxreg - FIRST_PSEUDO_REGISTER), sizeof (char))
- FIRST_PSEUDO_REGISTER;
reg_base_value_size = maxreg * 2;
reg_base_value = (rtx *) ggc_alloc_cleared (reg_base_value_size
* sizeof (rtx));
new_reg_base_value = (rtx *) xmalloc (reg_base_value_size * sizeof (rtx));
reg_seen = (char *) xmalloc (reg_base_value_size);
if (! reload_completed && flag_unroll_loops)
{
alias_invariant = (rtx *)xrealloc (alias_invariant,
reg_base_value_size * sizeof (rtx));
memset ((char *)alias_invariant, 0, reg_base_value_size * sizeof (rtx));
}
pass = 0;
do
{
changed = 0;
unique_id = 0;
copying_arguments = true;
memset ((char *) new_reg_base_value, 0, reg_base_value_size * sizeof (rtx));
memset ((char *) reg_seen, 0, reg_base_value_size);
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
&& GET_CODE (SET_DEST (set)) == REG
&& REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER)
{
unsigned int regno = REGNO (SET_DEST (set));
rtx src = SET_SRC (set);
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)))
{
reg_known_value[regno] = XEXP (note, 0);
reg_known_equiv_p[regno] = REG_NOTE_KIND (note) == REG_EQUIV;
}
else if (REG_N_SETS (regno) == 1
&& GET_CODE (src) == PLUS
&& GET_CODE (XEXP (src, 0)) == REG
&& REGNO (XEXP (src, 0)) >= FIRST_PSEUDO_REGISTER
&& (reg_known_value[REGNO (XEXP (src, 0))])
&& GET_CODE (XEXP (src, 1)) == CONST_INT)
{
rtx op0 = XEXP (src, 0);
op0 = reg_known_value[REGNO (op0)];
reg_known_value[regno]
= plus_constant (op0, INTVAL (XEXP (src, 1)));
reg_known_equiv_p[regno] = 0;
}
else if (REG_N_SETS (regno) == 1
&& ! rtx_varies_p (src, 1))
{
reg_known_value[regno] = src;
reg_known_equiv_p[regno] = 0;
}
}
}
else if (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
copying_arguments = false;
}
for (ui = 0; ui < reg_base_value_size; ui++)
{
if (new_reg_base_value[ui]
&& new_reg_base_value[ui] != reg_base_value[ui]
&& ! rtx_equal_p (new_reg_base_value[ui], reg_base_value[ui]))
{
reg_base_value[ui] = new_reg_base_value[ui];
changed = 1;
}
}
}
while (changed && ++pass < MAX_ALIAS_LOOP_PASSES);
for (i = FIRST_PSEUDO_REGISTER; i < maxreg; i++)
if (reg_known_value[i] == 0)
reg_known_value[i] = regno_reg_rtx[i];
pass = 0;
do
{
changed = 0;
pass++;
for (ui = 0; ui < reg_base_value_size; ui++)
{
rtx base = reg_base_value[ui];
if (base && GET_CODE (base) == REG)
{
unsigned int base_regno = REGNO (base);
if (base_regno == ui)
reg_base_value[ui] = 0;
else
reg_base_value[ui] = 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;
}
void
end_alias_analysis ()
{
free (reg_known_value + FIRST_PSEUDO_REGISTER);
reg_known_value = 0;
reg_known_value_size = 0;
free (reg_known_equiv_p + FIRST_PSEUDO_REGISTER);
reg_known_equiv_p = 0;
reg_base_value = 0;
reg_base_value_size = 0;
if (alias_invariant)
{
free (alias_invariant);
alias_invariant = 0;
}
}
#include "gt-alias.h"