#include "config.h"
#include "system.h"
#include "rtl.h"
#include "expr.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "flags.h"
#include "output.h"
#include "toplev.h"
#include "splay-tree.h"
typedef struct alias_set_entry {
int alias_set;
splay_tree children;
}* alias_set_entry;
static rtx canon_rtx PROTO((rtx));
static int rtx_equal_for_memref_p PROTO((rtx, rtx));
static rtx find_symbolic_term PROTO((rtx));
static int memrefs_conflict_p PROTO((int, rtx, int, rtx,
HOST_WIDE_INT));
static void record_set PROTO((rtx, rtx));
static rtx find_base_term PROTO((rtx));
static int base_alias_check PROTO((rtx, rtx, enum machine_mode,
enum machine_mode));
static rtx find_base_value PROTO((rtx));
static int mems_in_disjoint_alias_sets_p PROTO((rtx, rtx));
static int insert_subset_children PROTO((splay_tree_node,
void*));
static alias_set_entry get_alias_set_entry PROTO((int));
static rtx fixed_scalar_and_varying_struct_p PROTO((rtx, rtx, int (*)(rtx)));
static int aliases_everything_p PROTO((rtx));
static int write_dependence_p PROTO((rtx, rtx, 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
rtx *reg_base_value;
rtx *new_reg_base_value;
unsigned int reg_base_value_size;
#define REG_BASE_VALUE(X) \
((unsigned) REGNO (X) < reg_base_value_size ? reg_base_value[REGNO (X)] : 0)
static rtx *alias_invariant;
rtx *reg_known_value;
static int reg_known_value_size;
char *reg_known_equiv_p;
static int copying_arguments;
static splay_tree alias_sets;
static alias_set_entry
get_alias_set_entry (alias_set)
int alias_set;
{
splay_tree_node sn =
splay_tree_lookup (alias_sets, (splay_tree_key) alias_set);
return sn ? ((alias_set_entry) sn->value) : ((alias_set_entry) 0);
}
static int
mems_in_disjoint_alias_sets_p (mem1, mem2)
rtx mem1;
rtx mem2;
{
alias_set_entry ase;
#ifdef ENABLE_CHECKING
if (!flag_strict_aliasing &&
(MEM_ALIAS_SET (mem1) || MEM_ALIAS_SET (mem2)))
abort ();
#endif
if (current_function_stdarg || current_function_varargs)
return 0;
if (!MEM_ALIAS_SET (mem1) || !MEM_ALIAS_SET (mem2))
return 0;
if (MEM_ALIAS_SET (mem1) == MEM_ALIAS_SET (mem2))
return 0;
ase = get_alias_set_entry (MEM_ALIAS_SET (mem1));
if (ase && splay_tree_lookup (ase->children,
(splay_tree_key) MEM_ALIAS_SET (mem2)))
return 0;
ase = get_alias_set_entry (MEM_ALIAS_SET (mem2));
if (ase && splay_tree_lookup (ase->children,
(splay_tree_key) MEM_ALIAS_SET (mem1)))
return 0;
return 1;
}
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;
}
void
record_alias_subset (superset, subset)
int superset;
int subset;
{
alias_set_entry superset_entry;
alias_set_entry subset_entry;
if (superset == 0)
abort ();
superset_entry = get_alias_set_entry (superset);
if (!superset_entry)
{
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);
splay_tree_insert (alias_sets,
(splay_tree_key) superset,
(splay_tree_value) superset_entry);
}
subset_entry = get_alias_set_entry (subset);
if (subset_entry)
splay_tree_foreach (subset_entry->children,
insert_subset_children,
superset_entry->children);
splay_tree_insert (superset_entry->children,
(splay_tree_key) subset,
0);
}
static rtx
find_base_value (src)
register rtx src;
{
switch (GET_CODE (src))
{
case SYMBOL_REF:
case LABEL_REF:
return src;
case REG:
if (REGNO (src) < FIRST_PSEUDO_REGISTER && copying_arguments)
return new_reg_base_value[REGNO (src)];
if (REGNO (src) >= FIRST_PSEUDO_REGISTER
&& (unsigned) REGNO (src) < reg_base_value_size
&& reg_base_value[REGNO (src)])
return reg_base_value[REGNO (src)];
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 (GET_CODE (src_0) == REG)
{
temp = find_base_value (src_0);
if (temp)
src_0 = temp;
}
if (GET_CODE (src_1) == REG)
{
temp = find_base_value (src_1);
if (temp)
src_1 = temp;
}
if (GET_CODE (src_1) == CONST_INT
|| GET_CODE (src_0) == SYMBOL_REF
|| GET_CODE (src_0) == LABEL_REF
|| GET_CODE (src_0) == CONST)
return find_base_value (src_0);
if (GET_CODE (src_0) == CONST_INT
|| GET_CODE (src_1) == SYMBOL_REF
|| GET_CODE (src_1) == LABEL_REF
|| GET_CODE (src_1) == CONST)
return find_base_value (src_1);
if (GET_CODE (src_0) == REG && REGNO_POINTER_FLAG (REGNO (src_0)))
return find_base_value (src_0);
if (GET_CODE (src_1) == REG && REGNO_POINTER_FLAG (REGNO (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 ZERO_EXTEND:
case SIGN_EXTEND:
case HIGH:
return find_base_value (XEXP (src, 0));
default:
break;
}
return 0;
}
static char *reg_seen;
static int unique_id;
static void
record_set (dest, set)
rtx dest, set;
{
register int regno;
rtx src;
if (GET_CODE (dest) != REG)
return;
regno = REGNO (dest);
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 PLUS:
case MINUS:
if (XEXP (src, 0) != dest && XEXP (src, 1) != dest)
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)
int regno;
rtx val;
int invariant;
{
if ((unsigned) regno >= reg_base_value_size)
return;
if (invariant && alias_invariant)
alias_invariant[regno] = val;
if (GET_CODE (val) == REG)
{
if ((unsigned) REGNO (val) < reg_base_value_size)
{
reg_base_value[regno] = reg_base_value[REGNO (val)];
}
return;
}
reg_base_value[regno] = find_base_value (val);
}
static 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_for_output (x1, INTVAL (x0));
else if (GET_CODE (x1) == CONST_INT)
return plus_constant_for_output (x0, INTVAL (x1));
return gen_rtx_PLUS (GET_MODE (x), x0, x1);
}
}
else if (GET_CODE (x) == MEM)
{
rtx addr = canon_rtx (XEXP (x, 0));
if (addr != XEXP (x, 0))
{
rtx new = gen_rtx_MEM (GET_MODE (x), addr);
RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (x);
MEM_COPY_ATTRIBUTES (new, x);
MEM_ALIAS_SET (new) = MEM_ALIAS_SET (x);
x = new;
}
}
return x;
}
static int
rtx_equal_for_memref_p (x, y)
rtx x, y;
{
register int i;
register int j;
register enum rtx_code code;
register 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;
if (code == REG)
return REGNO (x) == REGNO (y);
if (code == LABEL_REF)
return XEXP (x, 0) == XEXP (y, 0);
if (code == SYMBOL_REF)
return XSTR (x, 0) == XSTR (y, 0);
if (code == CONST_INT)
return INTVAL (x) == INTVAL (y);
if (code == ADDRESSOF)
return REGNO (XEXP (x, 0)) == REGNO (XEXP (y, 0)) && XINT (x, 1) == XINT (y, 1);
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 '0':
break;
default:
abort ();
}
}
return 1;
}
static rtx
find_symbolic_term (x)
rtx x;
{
register int i;
register enum rtx_code code;
register 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)
register rtx x;
{
switch (GET_CODE (x))
{
case REG:
return REG_BASE_VALUE (x);
case ZERO_EXTEND:
case SIGN_EXTEND:
case HIGH:
case PRE_INC:
case PRE_DEC:
case POST_INC:
case POST_DEC:
return find_base_term (XEXP (x, 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 (REG_P (tmp1) && REGNO_POINTER_FLAG (REGNO (tmp1)))
return find_base_term (tmp1);
if (REG_P (tmp2) && REGNO_POINTER_FLAG (REGNO (tmp2)))
return find_base_term (tmp2);
tmp1 = find_base_term (tmp1);
tmp2 = find_base_term (tmp2);
if (tmp1
&& (GET_CODE (tmp1) == SYMBOL_REF
|| GET_CODE (tmp1) == LABEL_REF
|| (GET_CODE (tmp1) == ADDRESS
&& GET_MODE (tmp1) != VOIDmode)))
return tmp1;
if (tmp2
&& (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, 0)) == REG && GET_CODE (XEXP (x, 1)) == CONST_INT)
return REG_BASE_VALUE (XEXP (x, 0));
return 0;
case SYMBOL_REF:
case LABEL_REF:
return x;
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
|| GET_MODE_UNIT_SIZE (y_mode) < -INTVAL (XEXP (x, 1))))
return 1;
if (GET_CODE (y) == AND
&& (GET_CODE (XEXP (y, 1)) != CONST_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
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)
register rtx x, y;
int xsize, ysize;
HOST_WIDE_INT c;
{
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 (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)
&& (xsize == 0 || ysize == 0
|| (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, varies_p)
rtx mem1;
rtx mem2;
int (*varies_p) PROTO((rtx));
{
rtx mem1_addr = XEXP (mem1, 0);
rtx mem2_addr = XEXP (mem2, 0);
if (! flag_strict_aliasing)
return NULL_RTX;
if (MEM_SCALAR_P (mem1) && MEM_IN_STRUCT_P (mem2)
&& !varies_p (mem1_addr) && varies_p (mem2_addr))
return mem1;
if (MEM_IN_STRUCT_P (mem1) && MEM_SCALAR_P (mem2)
&& varies_p (mem1_addr) && !varies_p (mem2_addr))
return mem2;
return NULL_RTX;
}
static int
aliases_everything_p (mem)
rtx mem;
{
if (GET_MODE (mem) == QImode)
return 1;
if (GET_CODE (XEXP (mem, 0)) == AND)
return 1;
return 0;
}
int
true_dependence (mem, mem_mode, x, varies)
rtx mem;
enum machine_mode mem_mode;
rtx x;
int (*varies) PROTO((rtx));
{
register rtx x_addr, mem_addr;
if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
return 1;
if (DIFFERENT_ALIAS_SETS_P (x, mem))
return 0;
if (RTX_UNCHANGING_P (x) && ! RTX_UNCHANGING_P (mem))
return 0;
if (mem_mode == VOIDmode)
mem_mode = GET_MODE (mem);
if (! base_alias_check (XEXP (x, 0), XEXP (mem, 0), GET_MODE (x), mem_mode))
return 0;
x_addr = canon_rtx (XEXP (x, 0));
mem_addr = canon_rtx (XEXP (mem, 0));
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, varies);
}
static int
write_dependence_p (mem, x, writep)
rtx mem;
rtx x;
int writep;
{
rtx x_addr, mem_addr;
rtx fixed_scalar;
if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
return 1;
if (!writep && RTX_UNCHANGING_P (mem))
return 0;
if (! base_alias_check (XEXP (x, 0), XEXP (mem, 0), GET_MODE (x),
GET_MODE (mem)))
return 0;
x = canon_rtx (x);
mem = canon_rtx (mem);
if (DIFFERENT_ALIAS_SETS_P (x, mem))
return 0;
x_addr = XEXP (x, 0);
mem_addr = XEXP (mem, 0);
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, 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)
register rtx mem;
register rtx x;
{
return write_dependence_p (mem, x, 1);
}
static HARD_REG_SET argument_registers;
void
init_alias_once ()
{
register 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))
SET_HARD_REG_BIT (argument_registers, i);
alias_sets = splay_tree_new (splay_tree_compare_ints, 0, 0);
}
void
init_alias_analysis ()
{
int maxreg = max_reg_num ();
int changed, pass;
register int i;
register unsigned int ui;
register rtx insn;
reg_known_value_size = maxreg;
reg_known_value
= (rtx *) oballoc ((maxreg - FIRST_PSEUDO_REGISTER) * sizeof (rtx))
- FIRST_PSEUDO_REGISTER;
reg_known_equiv_p =
oballoc (maxreg - FIRST_PSEUDO_REGISTER) - FIRST_PSEUDO_REGISTER;
bzero ((char *) (reg_known_value + FIRST_PSEUDO_REGISTER),
(maxreg-FIRST_PSEUDO_REGISTER) * sizeof (rtx));
bzero (reg_known_equiv_p + FIRST_PSEUDO_REGISTER,
(maxreg - FIRST_PSEUDO_REGISTER) * sizeof (char));
reg_base_value_size = maxreg * 2;
reg_base_value = (rtx *)oballoc (reg_base_value_size * sizeof (rtx));
new_reg_base_value = (rtx *)alloca (reg_base_value_size * sizeof (rtx));
reg_seen = (char *)alloca (reg_base_value_size);
bzero ((char *) reg_base_value, reg_base_value_size * sizeof (rtx));
if (! reload_completed && flag_unroll_loops)
{
alias_invariant = (rtx *)xrealloc (alias_invariant,
reg_base_value_size * sizeof (rtx));
bzero ((char *)alias_invariant, reg_base_value_size * sizeof (rtx));
}
pass = 0;
do
{
changed = 0;
unique_id = 0;
copying_arguments = 1;
bzero ((char *) new_reg_base_value, reg_base_value_size * sizeof (rtx));
bzero ((char *) reg_seen, reg_base_value_size);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (argument_registers, i))
new_reg_base_value[i] = gen_rtx_ADDRESS (VOIDmode,
gen_rtx_REG (Pmode, i));
new_reg_base_value[STACK_POINTER_REGNUM]
= gen_rtx_ADDRESS (Pmode, stack_pointer_rtx);
new_reg_base_value[ARG_POINTER_REGNUM]
= gen_rtx_ADDRESS (Pmode, arg_pointer_rtx);
new_reg_base_value[FRAME_POINTER_REGNUM]
= gen_rtx_ADDRESS (Pmode, frame_pointer_rtx);
#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
new_reg_base_value[HARD_FRAME_POINTER_REGNUM]
= gen_rtx_ADDRESS (Pmode, hard_frame_pointer_rtx);
#endif
#if 0
if (struct_value_incoming_rtx
&& GET_CODE (struct_value_incoming_rtx) == REG)
new_reg_base_value[REGNO (struct_value_incoming_rtx)]
= gen_rtx_ADDRESS (Pmode, struct_value_incoming_rtx);
if (static_chain_rtx
&& GET_CODE (static_chain_rtx) == REG)
new_reg_base_value[REGNO (static_chain_rtx)]
= gen_rtx_ADDRESS (Pmode, static_chain_rtx);
#endif
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
rtx note, set;
if (GET_CODE (PATTERN (insn)) == SET
&& (find_reg_note (insn, REG_NOALIAS, NULL_RTX)))
record_set (SET_DEST (PATTERN (insn)), NULL_RTX);
else
note_stores (PATTERN (insn), record_set);
set = single_set (insn);
if (set != 0
&& GET_CODE (SET_DEST (set)) == REG
&& REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
&& (((note = find_reg_note (insn, REG_EQUAL, 0)) != 0
&& REG_N_SETS (REGNO (SET_DEST (set))) == 1)
|| (note = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != 0)
&& GET_CODE (XEXP (note, 0)) != EXPR_LIST
&& ! reg_overlap_mentioned_p (SET_DEST (set), XEXP (note, 0)))
{
int regno = REGNO (SET_DEST (set));
reg_known_value[regno] = XEXP (note, 0);
reg_known_equiv_p[regno] = REG_NOTE_KIND (note) == REG_EQUIV;
}
}
else if (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
copying_arguments = 0;
}
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);
new_reg_base_value = 0;
reg_seen = 0;
}
void
end_alias_analysis ()
{
reg_known_value = 0;
reg_base_value = 0;
reg_base_value_size = 0;
if (alias_invariant)
{
free ((char *)alias_invariant);
alias_invariant = 0;
}
}