/* Alias analysis for GNU C
- Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003
+ Free Software Foundation, Inc.
Contributed by John Carr (jfc@mit.edu).
This file is part of GCC.
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "rtl.h"
#include "tree.h"
#include "tm_p.h"
To see whether two alias sets can point to the same memory, we must
see if either alias set is a subset of the other. We need not trace
- past immediate descendents, however, since we propagate all
+ past immediate descendants, however, since we propagate all
grandchildren up one level.
Alias set zero is implicitly a superset of all other alias sets.
HOST_WIDE_INT alias_set;
/* The children of the alias set. These are not just the immediate
- children, but, in fact, all descendents. So, if we have:
+ children, but, in fact, all descendants. So, if we have:
struct T { struct S s; float f; }
static int nonlocal_referenced_p PARAMS ((rtx));
static int nonlocal_set_p_1 PARAMS ((rtx *, void *));
static int nonlocal_set_p PARAMS ((rtx));
+static void memory_modified_1 PARAMS ((rtx, rtx, void *));
/* Set up all info needed to perform alias analysis on memory references. */
current function performs nonlocal memory memory references for the
purposes of marking the function as a constant function. */
-static rtx *reg_base_value;
+static GTY((length ("reg_base_value_size"))) rtx *reg_base_value;
static rtx *new_reg_base_value;
static unsigned int reg_base_value_size; /* size of reg_base_value array */
+/* Static hunks of RTL used by the aliasing code; these are initialized
+ once per function to avoid unnecessary RTL allocations. */
+static GTY (()) rtx static_reg_base_value[FIRST_PSEUDO_REGISTER];
+
#define REG_BASE_VALUE(X) \
(REGNO (X) < reg_base_value_size \
? reg_base_value[REGNO (X)] : 0)
/* True when scanning insns from the start of the rtl to the
NOTE_INSN_FUNCTION_BEG note. */
-static int copying_arguments;
+static bool copying_arguments;
/* The splay-tree used to store the various alias set entries. */
static splay_tree alias_sets;
then they may not conflict. */
if ((t1 != 0 && readonly_fields_p (t1))
|| (t2 != 0 && readonly_fields_p (t2))
- || (t1 != 0 && TYPE_READONLY (t1))
- || (t2 != 0 && TYPE_READONLY (t2)))
+ || (t1 != 0 && lang_hooks.honor_readonly && TYPE_READONLY (t1))
+ || (t2 != 0 && lang_hooks.honor_readonly && TYPE_READONLY (t2)))
return 0;
/* If they are the same type, they must conflict. */
and references to functions, but that's different.) */
else if (TREE_CODE (t) == FUNCTION_TYPE)
set = 0;
+
+ /* Unless the language specifies otherwise, let vector types alias
+ their components. This avoids some nasty type punning issues in
+ normal usage. And indeed lets vectors be treated more like an
+ array slice. */
+ else if (TREE_CODE (t) == VECTOR_TYPE)
+ set = get_alias_set (TREE_TYPE (t));
+
else
/* Otherwise make a new alias set for this type. */
set = new_alias_set ();
The test above is not sufficient because the scheduler may move
a copy out of an arg reg past the NOTE_INSN_FUNCTION_BEGIN. */
if ((regno >= FIRST_PSEUDO_REGISTER || fixed_regs[regno])
- && regno < reg_base_value_size
- && reg_base_value[regno])
- return reg_base_value[regno];
+ && regno < reg_base_value_size)
+ {
+ /* If we're inside init_alias_analysis, use new_reg_base_value
+ to reduce the number of relaxation iterations. */
+ 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;
{
unsigned regno;
rtx src;
+ int n;
if (GET_CODE (dest) != REG)
return;
if (regno >= reg_base_value_size)
abort ();
+ /* If this spans multiple hard registers, then we must indicate that every
+ register has an unusable 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)
{
/* A CLOBBER wipes out any old value but does not prevent a previously
return GEN_INT (ioffset);
}
-/* Return nonzero if we can deterimine the exprs corresponding to memrefs
+/* Return nonzero if we can determine the exprs corresponding to memrefs
X and Y and they do not overlap. */
static int
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)
{
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;
varies);
}
-/* Returns non-zero if a write to X might alias a previous read from
- (or, if WRITEP is non-zero, a write to) MEM. */
+/* Returns nonzero if a write to X might alias a previous read from
+ (or, if WRITEP is nonzero, a write to) MEM. */
static int
write_dependence_p (mem, x, writep)
return 0;
}
-/* Returns non-zero if X might mention something which is not
+/* Returns nonzero if X might mention something which is not
local to the function and is not constant. */
static int
return 0;
}
-/* Returns non-zero if X might reference something which is not
+/* Returns nonzero if X might reference something which is not
local to the function and is not constant. */
static int
return 0;
}
-/* Returns non-zero if X might set something which is not
+/* Returns nonzero if X might set something which is not
local to the function and is not constant. */
static int
}
\f
-static HARD_REG_SET argument_registers;
-
void
init_alias_once ()
{
numbers, so translate if necessary due to register windows. */
if (FUNCTION_ARG_REGNO_P (OUTGOING_REGNO (i))
&& HARD_REGNO_MODE_OK (i, Pmode))
- SET_HARD_REG_BIT (argument_registers, i);
+ 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);
}
+/* Set MEMORY_MODIFIED when X modifies DATA (that is assumed
+ to be memory reference. */
+static bool memory_modified;
+static void
+memory_modified_1 (x, pat, data)
+ rtx x, pat ATTRIBUTE_UNUSED;
+ void *data;
+{
+ if (GET_CODE (x) == MEM)
+ {
+ if (anti_dependence (x, (rtx)data) || output_dependence (x, (rtx)data))
+ memory_modified = true;
+ }
+}
+
+
+/* Return true when INSN possibly modify memory contents of MEM
+ (ie address can be modified). */
+bool
+memory_modified_in_insn_p (mem, insn)
+ rtx mem, insn;
+{
+ if (!INSN_P (insn))
+ return false;
+ memory_modified = false;
+ note_stores (PATTERN (insn), memory_modified_1, mem);
+ return memory_modified;
+}
+
/* Initialize the aliasing machinery. Initialize the REG_KNOWN_VALUE
array. */
optimization. Loop unrolling can create a large number of
registers. */
reg_base_value_size = maxreg * 2;
- reg_base_value = (rtx *) xcalloc (reg_base_value_size, sizeof (rtx));
- ggc_add_rtx_root (reg_base_value, reg_base_value_size);
+ 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);
/* We're at the start of the function each iteration through the
loop, so we're copying arguments. */
- copying_arguments = 1;
+ copying_arguments = true;
/* Wipe the potential alias information clean for this pass. */
memset ((char *) new_reg_base_value, 0, reg_base_value_size * sizeof (rtx));
The address expression is VOIDmode for an argument and
Pmode for other registers. */
- 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
+ memcpy (new_reg_base_value, static_reg_base_value,
+ FIRST_PSEUDO_REGISTER * sizeof (rtx));
/* Walk the insns adding values to the new_reg_base_value array. */
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
}
else if (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
- copying_arguments = 0;
+ copying_arguments = false;
}
/* Now propagate values from new_reg_base_value to reg_base_value. */
reg_known_value_size = 0;
free (reg_known_equiv_p + FIRST_PSEUDO_REGISTER);
reg_known_equiv_p = 0;
- if (reg_base_value)
- {
- ggc_del_root (reg_base_value);
- free (reg_base_value);
- reg_base_value = 0;
- }
+ reg_base_value = 0;
reg_base_value_size = 0;
if (alias_invariant)
{
alias_invariant = 0;
}
}
+
+#include "gt-alias.h"