/* 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. */
/* 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);
-
- alias_sets = splay_tree_new (splay_tree_compare_ints, 0, 0);
-}
-
-/* Per-function initializer for the aliasing code.
-
- Allocate RTL for argument and other special use registers once
- per function here intead of multiple times per function in
- init_alias_analysis. */
-
-void
-init_alias_once_per_function ()
-{
- int i;
-
- /* Generate and mark all hard registers which may contain an address.
- The stack, frame and argument pointers may contain an address.
- An argument register which can hold a Pmode value may contain
- an address even if it is not in BASE_REGS.
-
- 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))
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]
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
/* 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] = static_reg_base_value[i];
+ memcpy (new_reg_base_value, static_reg_base_value,
+ FIRST_PSEUDO_REGISTER * sizeof (rtx));
- new_reg_base_value[STACK_POINTER_REGNUM]
- = static_reg_base_value[STACK_POINTER_REGNUM];
- new_reg_base_value[ARG_POINTER_REGNUM]
- = static_reg_base_value[ARG_POINTER_REGNUM];
- new_reg_base_value[FRAME_POINTER_REGNUM]
- = static_reg_base_value[FRAME_POINTER_REGNUM];
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
- new_reg_base_value[HARD_FRAME_POINTER_REGNUM]
- = static_reg_base_value[HARD_FRAME_POINTER_REGNUM];
-#endif
/* 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. */