Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
Contributed by John Carr (jfc@mit.edu).
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
#include "config.h"
#include "system.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 decendents, however, since we propagate all
+ past immediate descendents, 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 decendents. So, if we have:
+ children, but, in fact, all descendents. So, if we have:
struct T { struct S s; float f; }
static int write_dependence_p PARAMS ((rtx, rtx, int));
static int nonlocal_mentioned_p PARAMS ((rtx));
-static int loop_p PARAMS ((void));
-
/* Set up all info needed to perform alias analysis on memory references. */
/* Returns the size in bytes of the mode of X. */
!= (t2 != 0 && AGGREGATE_TYPE_P (t2)))
return 0;
- /* Otherwise they conflict only if the alias sets conflict. */
+ /* Otherwise they conflict only if the alias sets conflict. */
return alias_sets_conflict_p (t1 ? get_alias_set (t1) : 0,
t2 ? get_alias_set (t2) : 0);
}
case '3':
d0 = find_base_decl (TREE_OPERAND (t, 0));
d1 = find_base_decl (TREE_OPERAND (t, 1));
- d0 = find_base_decl (TREE_OPERAND (t, 0));
d2 = find_base_decl (TREE_OPERAND (t, 2));
/* Set any nonzero values from the last, then from the first. */
return 0;
/* We can be passed either an expression or a type. This and the
- language-specific routine may make mutually-recursive calls to
- each other to figure out what to do. At each juncture, we see if
- this is a tree that the language may need to handle specially.
- First handle things that aren't types and start by removing nops
- since we care only about the actual object. */
+ language-specific routine may make mutually-recursive calls to each other
+ to figure out what to do. At each juncture, we see if this is a tree
+ that the language may need to handle specially. First handle things that
+ aren't types and start by removing nops since we care only about the
+ actual object. Also replace PLACEHOLDER_EXPRs and pick up the outermost
+ object that we could have a pointer to. */
if (! TYPE_P (t))
{
- while (TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR
- || TREE_CODE (t) == NON_LVALUE_EXPR)
- t = TREE_OPERAND (t, 0);
+ /* Remove any NOPs and see what any PLACEHOLD_EXPRs will expand to. */
+ while (((TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR)
+ && (TYPE_MODE (TREE_TYPE (t))
+ == TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 0)))))
+ || TREE_CODE (t) == NON_LVALUE_EXPR
+ || TREE_CODE (t) == PLACEHOLDER_EXPR
+ || (handled_component_p (t) && ! can_address_p (t)))
+ {
+ /* Give the language a chance to do something with this tree
+ before we go inside it. */
+ if ((set = lang_get_alias_set (t)) != -1)
+ return set;
+
+ if (TREE_CODE (t) == PLACEHOLDER_EXPR)
+ t = find_placeholder (t, 0);
+ else
+ t = TREE_OPERAND (t, 0);
+ }
/* Now give the language a chance to do something but record what we
gave it this time. */
if ((set = lang_get_alias_set (t)) != -1)
return set;
- /* Now loop the same way as get_inner_reference and get the alias
- set to use. Pick up the outermost object that we could have
- a pointer to. */
- while (handled_component_p (t) && ! can_address_p (t))
- t = TREE_OPERAND (t, 0);
-
+ /* Check for accesses through restrict-qualified pointers. */
if (TREE_CODE (t) == INDIRECT_REF)
{
- /* Check for accesses through restrict-qualified pointers. */
tree decl = find_base_decl (TREE_OPERAND (t, 0));
if (decl && DECL_POINTER_ALIAS_SET_KNOWN_P (decl))
return 0;
}
+ /* If we've already determined the alias set for this decl, just
+ return it. This is necessary for C++ anonymous unions, whose
+ component variables don't look like union members (boo!). */
+ if (TREE_CODE (t) == VAR_DECL
+ && DECL_RTL_SET_P (t) && GET_CODE (DECL_RTL (t)) == MEM)
+ return MEM_ALIAS_SET (DECL_RTL (t));
+
/* Give the language another chance to do something special. */
if (orig_t != t
&& (set = lang_get_alias_set (t)) != -1)
alias_set_entry superset_entry;
alias_set_entry subset_entry;
+ /* It is possible in complex type situations for both sets to be the same,
+ in which case we can ignore this operation. */
+ if (superset == subset)
+ return;
+
if (superset == 0)
abort ();
static rtx
find_base_value (src)
- register rtx src;
+ rtx src;
{
unsigned int regno;
switch (GET_CODE (src))
if (GET_CODE (src) != PLUS && GET_CODE (src) != MINUS)
break;
- /* ... fall through ... */
+ /* ... fall through ... */
case PLUS:
case MINUS:
case AND:
/* If the second operand is constant set the base
- address to the first operand. */
+ address to the first operand. */
if (GET_CODE (XEXP (src, 1)) == CONST_INT && INTVAL (XEXP (src, 1)) != 0)
return find_base_value (XEXP (src, 0));
return 0;
rtx dest, set;
void *data ATTRIBUTE_UNUSED;
{
- register unsigned regno;
+ unsigned regno;
rtx src;
if (GET_CODE (dest) != REG)
reg_base_value[regno] = find_base_value (val);
}
+/* Clear alias info for a register. This is used if an RTL transformation
+ changes the value of a register. This is used in flow by AUTO_INC_DEC
+ optimizations. We don't need to clear reg_base_value, since flow only
+ changes the offset. */
+
+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;
+}
+
/* Returns a canonical version of X, from the point of view alias
analysis. (For example, if X is a MEM whose address is a register,
and the register has a known value (say a SYMBOL_REF), then a MEM
MEM alone, but need to return the canonicalized MEM with
all the flags with their original values. */
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);
+ x = replace_equiv_address_nv (x, canon_rtx (XEXP (x, 0)));
- MEM_COPY_ATTRIBUTES (new, x);
- x = new;
- }
- }
return x;
}
rtx_equal_for_memref_p (x, y)
rtx x, y;
{
- register int i;
- register int j;
- register enum rtx_code code;
- register const char *fmt;
+ int i;
+ int j;
+ enum rtx_code code;
+ const char *fmt;
if (x == 0 && y == 0)
return 1;
/* Some RTL can be compared without a recursive examination. */
switch (code)
{
+ case VALUE:
+ return CSELIB_VAL_PTR (x) == CSELIB_VAL_PTR (y);
+
case REG:
return REGNO (x) == REGNO (y);
return 0;
break;
+ /* This can happen for asm operands. */
+ case 's':
+ if (strcmp (XSTR (x, i), XSTR (y, i)))
+ return 0;
+ break;
+
/* This can happen for an asm which clobbers memory. */
case '0':
break;
find_symbolic_term (x)
rtx x;
{
- register int i;
- register enum rtx_code code;
- register const char *fmt;
+ int i;
+ enum rtx_code code;
+ const char *fmt;
code = GET_CODE (x);
if (code == SYMBOL_REF || code == LABEL_REF)
static rtx
find_base_term (x)
- register rtx x;
+ rtx x;
{
cselib_val *val;
struct elt_loc_list *l;
return 1;
if (GET_CODE (x) == AND
&& (GET_CODE (XEXP (x, 1)) != CONST_INT
- || GET_MODE_UNIT_SIZE (y_mode) < -INTVAL (XEXP (x, 1))))
+ || (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))))
+ || (int) GET_MODE_UNIT_SIZE (x_mode) < -INTVAL (XEXP (y, 1))))
return 1;
/* Differing symbols never alias. */
return 0;
if (flag_argument_noalias > 1)
return 0;
- /* Weak noalias assertion (arguments are distinct, but may match globals). */
+ /* Weak noalias assertion (arguments are distinct, but may match globals). */
return ! (GET_MODE (x_base) == VOIDmode && GET_MODE (y_base) == VOIDmode);
}
static int
memrefs_conflict_p (xsize, x, ysize, y, c)
- register rtx x, y;
+ rtx x, y;
int xsize, ysize;
HOST_WIDE_INT c;
{
rtx x;
int (*varies) PARAMS ((rtx, int));
{
- register rtx x_addr, mem_addr;
+ rtx x_addr, mem_addr;
rtx base;
if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
enum machine_mode mem_mode;
int (*varies) PARAMS ((rtx, int));
{
- register rtx x_addr;
+ rtx x_addr;
if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
return 1;
int
output_dependence (mem, x)
- register rtx mem;
- register rtx x;
+ rtx mem;
+ rtx x;
{
return write_dependence_p (mem, x, /*writep=*/1);
}
rtx x;
{
rtx base;
- register RTX_CODE code;
+ RTX_CODE code;
int regno;
code = GET_CODE (x);
{
/* Constant functions can be constant if they don't use
scratch memory used to mark function w/o side effects. */
- if (code == CALL_INSN && CONST_CALL_P (x))
+ if (code == CALL_INSN && CONST_OR_PURE_CALL_P (x))
{
x = CALL_INSN_FUNCTION_USAGE (x);
if (x == 0)
/* Recursively scan the operands of this expression. */
{
- register const char *fmt = GET_RTX_FORMAT (code);
- register int i;
+ const char *fmt = GET_RTX_FORMAT (code);
+ int i;
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
}
else if (fmt[i] == 'E')
{
- register int j;
+ int j;
for (j = 0; j < XVECLEN (x, i); j++)
if (nonlocal_mentioned_p (XVECEXP (x, i, j)))
return 1;
return 0;
}
-/* Return non-zero if a loop (natural or otherwise) is present.
- Inspired by Depth_First_Search_PP described in:
-
- Advanced Compiler Design and Implementation
- Steven Muchnick
- Morgan Kaufmann, 1997
-
- and heavily borrowed from flow_depth_first_order_compute. */
-
-static int
-loop_p ()
-{
- edge *stack;
- int *pre;
- int *post;
- int sp;
- int prenum = 1;
- int postnum = 1;
- sbitmap visited;
-
- /* Allocate the preorder and postorder number arrays. */
- pre = (int *) xcalloc (n_basic_blocks, sizeof (int));
- post = (int *) xcalloc (n_basic_blocks, sizeof (int));
-
- /* Allocate stack for back-tracking up CFG. */
- stack = (edge *) xmalloc ((n_basic_blocks + 1) * sizeof (edge));
- sp = 0;
-
- /* Allocate bitmap to track nodes that have been visited. */
- visited = sbitmap_alloc (n_basic_blocks);
-
- /* None of the nodes in the CFG have been visited yet. */
- sbitmap_zero (visited);
-
- /* Push the first edge on to the stack. */
- stack[sp++] = ENTRY_BLOCK_PTR->succ;
-
- while (sp)
- {
- edge e;
- basic_block src;
- basic_block dest;
-
- /* Look at the edge on the top of the stack. */
- e = stack[sp - 1];
- src = e->src;
- dest = e->dest;
-
- /* Check if the edge destination has been visited yet. */
- if (dest != EXIT_BLOCK_PTR && ! TEST_BIT (visited, dest->index))
- {
- /* Mark that we have visited the destination. */
- SET_BIT (visited, dest->index);
-
- pre[dest->index] = prenum++;
-
- if (dest->succ)
- {
- /* Since the DEST node has been visited for the first
- time, check its successors. */
- stack[sp++] = dest->succ;
- }
- else
- post[dest->index] = postnum++;
- }
- else
- {
- if (dest != EXIT_BLOCK_PTR
- && pre[src->index] >= pre[dest->index]
- && post[dest->index] == 0)
- break;
-
- if (! e->succ_next && src != ENTRY_BLOCK_PTR)
- post[src->index] = postnum++;
-
- if (e->succ_next)
- stack[sp - 1] = e->succ_next;
- else
- sp--;
- }
- }
-
- free (pre);
- free (post);
- free (stack);
- sbitmap_free (visited);
-
- return sp;
-}
-
/* Mark the function if it is constant. */
void
return;
/* A loop might not return which counts as a side effect. */
- if (loop_p ())
+ if (mark_dfs_back_edges ())
return;
nonlocal_mentioned = 0;
void
init_alias_once ()
{
- register int i;
+ int i;
#ifndef OUTGOING_REGNO
#define OUTGOING_REGNO(N) N
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
/* Check whether this register can hold an incoming pointer
argument. FUNCTION_ARG_REGNO_P tests outgoing register
- numbers, so translate if necessary due to register windows. */
+ 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);
{
int maxreg = max_reg_num ();
int changed, pass;
- register int i;
- register unsigned int ui;
- register rtx insn;
+ int i;
+ unsigned int ui;
+ rtx insn;
reg_known_value_size = maxreg;
/* If this insn has a noalias note, process it, Otherwise,
scan for sets. A simple set will have no side effects
- which could change the base value of any other register. */
+ which could change the base value of any other register. */
if (GET_CODE (PATTERN (insn)) == SET
&& REG_NOTES (insn) != 0