Makefile.in (print-rtl.o): Depend on TREE_H.
* Makefile.in (print-rtl.o): Depend on TREE_H. * alias.c (get_alias_set): Make two passes over objects to first see if inner object is access via restricted pointer. Defer allocating alias set for restricted pointer until here. Call find_placeholder with second arg nonzero. Minor cleanups. * emit-rtl.c (set_mem_attributes): Set more attributes. (set_mem_align, change_address, adjust_address_1): New functions. (change_address_1): Now static. (adjust_address, adjust_address_nv): Deleted. (replace_equiv_address): Call change_address_1. * expr.c (get_inner_reference): Handle PLACEHOLDER_EXPR. (find_placeholder): Get starting point from PLIST arg. (expand_expr, case PLACEHOLDER_EXPR): Initialize find_placeholder arg. * expr.h (set_mem_align, change_address, adjust_address_1): New decls. (adjust_address, adjust_address_nv): New macros. * print-rtl.c (tree.h): New include. (print_rtx, case MEM): Print all memory attributes. From-SVN: r46313
This commit is contained in:
parent
4d8f669f94
commit
738cc47245
@ -1,3 +1,24 @@
|
||||
Wed Oct 17 05:26:39 2001 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
|
||||
|
||||
* Makefile.in (print-rtl.o): Depend on TREE_H.
|
||||
* alias.c (get_alias_set): Make two passes over objects to first
|
||||
see if inner object is access via restricted pointer.
|
||||
Defer allocating alias set for restricted pointer until here.
|
||||
Call find_placeholder with second arg nonzero.
|
||||
Minor cleanups.
|
||||
* emit-rtl.c (set_mem_attributes): Set more attributes.
|
||||
(set_mem_align, change_address, adjust_address_1): New functions.
|
||||
(change_address_1): Now static.
|
||||
(adjust_address, adjust_address_nv): Deleted.
|
||||
(replace_equiv_address): Call change_address_1.
|
||||
* expr.c (get_inner_reference): Handle PLACEHOLDER_EXPR.
|
||||
(find_placeholder): Get starting point from PLIST arg.
|
||||
(expand_expr, case PLACEHOLDER_EXPR): Initialize find_placeholder arg.
|
||||
* expr.h (set_mem_align, change_address, adjust_address_1): New decls.
|
||||
(adjust_address, adjust_address_nv): New macros.
|
||||
* print-rtl.c (tree.h): New include.
|
||||
(print_rtx, case MEM): Print all memory attributes.
|
||||
|
||||
2001-10-17 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* config/alpha/alpha.c (direct_call_operand): Don't fall off end.
|
||||
|
@ -1381,8 +1381,8 @@ rtl-error.o: rtl-error.c system.h $(RTL_H) $(INSN_ATTR_H) insn-config.h \
|
||||
rtl.o : rtl.c $(GCONFIG_H) $(SYSTEM_H) $(RTL_H) real.h $(GGC_H) errors.h
|
||||
$(CC) -c $(ALL_CFLAGS) -DGENERATOR_FILE $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
|
||||
|
||||
print-rtl.o : print-rtl.c $(GCONFIG_H) $(SYSTEM_H) $(RTL_H) hard-reg-set.h \
|
||||
$(BASIC_BLOCK_H)
|
||||
print-rtl.o : print-rtl.c $(GCONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) \
|
||||
hard-reg-set.h $(BASIC_BLOCK_H)
|
||||
$(CC) -c $(ALL_CFLAGS) -DGENERATOR_FILE $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
|
||||
|
||||
rtlanal.o : rtlanal.c $(CONFIG_H) $(SYSTEM_H) toplev.h $(RTL_H) hard-reg-set.h
|
||||
|
115
gcc/alias.c
115
gcc/alias.c
@ -99,7 +99,7 @@ static int can_address_p PARAMS ((tree));
|
||||
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 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)));
|
||||
@ -458,7 +458,6 @@ HOST_WIDE_INT
|
||||
get_alias_set (t)
|
||||
tree t;
|
||||
{
|
||||
tree orig_t;
|
||||
HOST_WIDE_INT set;
|
||||
|
||||
/* If we're not doing any alias analysis, just assume everything
|
||||
@ -473,14 +472,76 @@ get_alias_set (t)
|
||||
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. */
|
||||
aren't types. */
|
||||
if (! TYPE_P (t))
|
||||
{
|
||||
/* Remove any NOPs and see what any PLACEHOLD_EXPRs will expand to. */
|
||||
tree inner = t;
|
||||
tree placeholder_ptr = 0;
|
||||
|
||||
/* First see if the actual object referenced is an INDIRECT_REF from a
|
||||
restrict-qualified pointer or a "void *". Start by removing nops
|
||||
since we care only about the actual object. Also replace
|
||||
PLACEHOLDER_EXPRs. */
|
||||
while (((TREE_CODE (inner) == NOP_EXPR
|
||||
|| TREE_CODE (inner) == CONVERT_EXPR)
|
||||
&& (TYPE_MODE (TREE_TYPE (inner))
|
||||
== TYPE_MODE (TREE_TYPE (TREE_OPERAND (inner, 0)))))
|
||||
|| TREE_CODE (inner) == NON_LVALUE_EXPR
|
||||
|| 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);
|
||||
}
|
||||
|
||||
/* Check for accesses through restrict-qualified pointers. */
|
||||
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 we haven't computed the actual alias set, do it now. */
|
||||
if (DECL_POINTER_ALIAS_SET (decl) == -2)
|
||||
{
|
||||
/* No two restricted pointers can point at the same thing.
|
||||
However, a restricted pointer can point at the same thing
|
||||
as an unrestricted pointer, if that unrestricted pointer
|
||||
is based on the restricted pointer. So, we make the
|
||||
alias set for the restricted pointer a subset of the
|
||||
alias set for the type pointed to by the type of the
|
||||
decl. */
|
||||
HOST_WIDE_INT pointed_to_alias_set
|
||||
= get_alias_set (TREE_TYPE (TREE_TYPE (decl)));
|
||||
|
||||
if (pointed_to_alias_set == 0)
|
||||
/* It's not legal to make a subset of alias set zero. */
|
||||
;
|
||||
else
|
||||
{
|
||||
DECL_POINTER_ALIAS_SET (decl) = new_alias_set ();
|
||||
record_alias_subset (pointed_to_alias_set,
|
||||
DECL_POINTER_ALIAS_SET (decl));
|
||||
}
|
||||
}
|
||||
|
||||
/* We use the alias set indicated in the declaration. */
|
||||
return DECL_POINTER_ALIAS_SET (decl);
|
||||
}
|
||||
|
||||
/* If we have an INDIRECT_REF via a void pointer, we don't
|
||||
know anything about what that might alias. */
|
||||
else if (TREE_CODE (TREE_TYPE (inner)) == VOID_TYPE)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Otherwise, pick up the outermost object that we could have a pointer
|
||||
to, processing conversion and PLACEHOLDER_EXPR as above. */
|
||||
placeholder_ptr = 0;
|
||||
while (((TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR)
|
||||
&& (TYPE_MODE (TREE_TYPE (t))
|
||||
&& (TYPE_MODE (TREE_TYPE (t))
|
||||
== TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 0)))))
|
||||
|| TREE_CODE (t) == NON_LVALUE_EXPR
|
||||
|| TREE_CODE (t) == PLACEHOLDER_EXPR
|
||||
@ -492,44 +553,22 @@ get_alias_set (t)
|
||||
return set;
|
||||
|
||||
if (TREE_CODE (t) == PLACEHOLDER_EXPR)
|
||||
t = find_placeholder (t, 0);
|
||||
t = find_placeholder (t, &placeholder_ptr);
|
||||
else
|
||||
t = TREE_OPERAND (t, 0);
|
||||
}
|
||||
|
||||
/* Now give the language a chance to do something but record what we
|
||||
gave it this time. */
|
||||
orig_t = t;
|
||||
/* Give the language another chance to do something. */
|
||||
if ((set = lang_get_alias_set (t)) != -1)
|
||||
return set;
|
||||
|
||||
/* Check for accesses through restrict-qualified pointers. */
|
||||
if (TREE_CODE (t) == INDIRECT_REF)
|
||||
{
|
||||
tree decl = find_base_decl (TREE_OPERAND (t, 0));
|
||||
|
||||
if (decl && DECL_POINTER_ALIAS_SET_KNOWN_P (decl))
|
||||
/* We use the alias set indicated in the declaration. */
|
||||
return DECL_POINTER_ALIAS_SET (decl);
|
||||
|
||||
/* If we have an INDIRECT_REF via a void pointer, we don't
|
||||
know anything about what that might alias. */
|
||||
if (TREE_CODE (TREE_TYPE (t)) == VOID_TYPE)
|
||||
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 we've already determined the alias set for a 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)
|
||||
return set;
|
||||
|
||||
/* Now all we care about is the type. */
|
||||
t = TREE_TYPE (t);
|
||||
}
|
||||
@ -537,16 +576,12 @@ get_alias_set (t)
|
||||
/* Variant qualifiers don't affect the alias set, so get the main
|
||||
variant. If this is a type with a known alias set, return it. */
|
||||
t = TYPE_MAIN_VARIANT (t);
|
||||
if (TYPE_P (t) && TYPE_ALIAS_SET_KNOWN_P (t))
|
||||
if (TYPE_ALIAS_SET_KNOWN_P (t))
|
||||
return TYPE_ALIAS_SET (t);
|
||||
|
||||
/* See if the language has special handling for this type. */
|
||||
if ((set = lang_get_alias_set (t)) != -1)
|
||||
{
|
||||
/* If the alias set is now known, we are done. */
|
||||
if (TYPE_ALIAS_SET_KNOWN_P (t))
|
||||
return TYPE_ALIAS_SET (t);
|
||||
}
|
||||
return set;
|
||||
|
||||
/* There are no objects of FUNCTION_TYPE, so there's no point in
|
||||
using up an alias set for them. (There are, of course, pointers
|
||||
|
165
gcc/emit-rtl.c
165
gcc/emit-rtl.c
@ -178,6 +178,8 @@ static rtx make_jump_insn_raw PARAMS ((rtx));
|
||||
static rtx make_call_insn_raw PARAMS ((rtx));
|
||||
static rtx find_line_note PARAMS ((rtx));
|
||||
static void mark_sequence_stack PARAMS ((struct sequence_stack *));
|
||||
static rtx change_address_1 PARAMS ((rtx, enum machine_mode, rtx,
|
||||
int));
|
||||
static void unshare_all_rtl_1 PARAMS ((rtx));
|
||||
static void unshare_all_decls PARAMS ((tree));
|
||||
static void reset_used_decls PARAMS ((tree));
|
||||
@ -1652,14 +1654,6 @@ set_mem_attributes (ref, t, objectp)
|
||||
|
||||
type = TYPE_P (t) ? t : TREE_TYPE (t);
|
||||
|
||||
/* Get the alias set from the expression or type (perhaps using a
|
||||
front-end routine) and then copy bits from the type. */
|
||||
|
||||
/* It is incorrect to set RTX_UNCHANGING_P from TREE_READONLY (type)
|
||||
here, because, in C and C++, the fact that a location is accessed
|
||||
through a const expression does not mean that the value there can
|
||||
never change. */
|
||||
|
||||
/* If we have already set DECL_RTL = ref, get_alias_set will get the
|
||||
wrong answer, as it assumes that DECL_RTL already has the right alias
|
||||
info. Callers should not set DECL_RTL until after the call to
|
||||
@ -1667,8 +1661,15 @@ set_mem_attributes (ref, t, objectp)
|
||||
if (DECL_P (t) && ref == DECL_RTL_IF_SET (t))
|
||||
abort ();
|
||||
|
||||
/* Get the alias set from the expression or type (perhaps using a
|
||||
front-end routine). */
|
||||
set_mem_alias_set (ref, get_alias_set (t));
|
||||
|
||||
/* It is incorrect to set RTX_UNCHANGING_P from TREE_READONLY (type)
|
||||
here, because, in C and C++, the fact that a location is accessed
|
||||
through a const expression does not mean that the value there can
|
||||
never change. */
|
||||
|
||||
MEM_VOLATILE_P (ref) = TYPE_VOLATILE (type);
|
||||
MEM_IN_STRUCT_P (ref) = AGGREGATE_TYPE_P (type);
|
||||
|
||||
@ -1677,7 +1678,14 @@ set_mem_attributes (ref, t, objectp)
|
||||
if (objectp && ! AGGREGATE_TYPE_P (type))
|
||||
MEM_SCALAR_P (ref) = 1;
|
||||
|
||||
/* If T is a type, this is all we can do. Otherwise, we may be able
|
||||
/* If the size is known, we can set that. */
|
||||
if (TYPE_SIZE_UNIT (type) && host_integerp (TYPE_SIZE_UNIT (type), 1))
|
||||
MEM_ATTRS (ref)
|
||||
= get_mem_attrs (MEM_ALIAS_SET (ref), MEM_DECL (ref), MEM_OFFSET (ref),
|
||||
GEN_INT (tree_low_cst (TYPE_SIZE_UNIT (type), 1)),
|
||||
MEM_ALIGN (ref));
|
||||
|
||||
/* If T is a type, there's nothing more we can do. Otherwise, we may be able
|
||||
to deduce some more information about the expression. */
|
||||
if (TYPE_P (t))
|
||||
return;
|
||||
@ -1686,17 +1694,27 @@ set_mem_attributes (ref, t, objectp)
|
||||
if (TREE_THIS_VOLATILE (t))
|
||||
MEM_VOLATILE_P (ref) = 1;
|
||||
|
||||
/* Now see if we can say more about whether it's an aggregate or
|
||||
scalar. If we already know it's an aggregate, don't bother. */
|
||||
if (MEM_IN_STRUCT_P (ref))
|
||||
return;
|
||||
|
||||
/* Now remove any NOPs: they don't change what the underlying object is.
|
||||
Likewise for SAVE_EXPR. */
|
||||
while (TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR
|
||||
|| TREE_CODE (t) == NON_LVALUE_EXPR || TREE_CODE (t) == SAVE_EXPR)
|
||||
t = TREE_OPERAND (t, 0);
|
||||
|
||||
/* If this is a decl, set the attributes of the MEM from it. */
|
||||
if (DECL_P (t))
|
||||
MEM_ATTRS (ref)
|
||||
= get_mem_attrs
|
||||
(MEM_ALIAS_SET (ref), t, GEN_INT (0),
|
||||
(TYPE_SIZE_UNIT (TREE_TYPE (t))
|
||||
&& host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (t)), 1))
|
||||
? GEN_INT (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (t)), 1))
|
||||
: 0, DECL_ALIGN (t) / BITS_PER_UNIT);
|
||||
|
||||
/* Now see if we can say more about whether it's an aggregate or
|
||||
scalar. If we already know it's an aggregate, don't bother. */
|
||||
if (MEM_IN_STRUCT_P (ref))
|
||||
return;
|
||||
|
||||
/* Since we already know the type isn't an aggregate, if this is a decl,
|
||||
it must be a scalar. Or if it is a reference into an aggregate,
|
||||
this is part of an aggregate. Otherwise we don't know. */
|
||||
@ -1715,7 +1733,6 @@ set_mem_alias_set (mem, set)
|
||||
rtx mem;
|
||||
HOST_WIDE_INT set;
|
||||
{
|
||||
/* It would be nice to enable this check, but we can't quite yet. */
|
||||
#ifdef ENABLE_CHECKING
|
||||
/* If the new and old alias sets don't conflict, something is wrong. */
|
||||
if (!alias_sets_conflict_p (set, MEM_ALIAS_SET (mem)))
|
||||
@ -1725,15 +1742,25 @@ set_mem_alias_set (mem, set)
|
||||
MEM_ATTRS (mem) = get_mem_attrs (set, MEM_DECL (mem), MEM_OFFSET (mem),
|
||||
MEM_SIZE (mem), MEM_ALIGN (mem));
|
||||
}
|
||||
|
||||
/* Return a memory reference like MEMREF, but with its mode changed
|
||||
to MODE and its address changed to ADDR.
|
||||
(VOIDmode means don't change the mode.
|
||||
NULL for ADDR means don't change the address.)
|
||||
VALIDATE is nonzero if the returned memory location is required to be
|
||||
valid. */
|
||||
|
||||
rtx
|
||||
/* Set the alignment of MEM to ALIGN. */
|
||||
|
||||
void
|
||||
set_mem_align (mem, align)
|
||||
rtx mem;
|
||||
unsigned int align;
|
||||
{
|
||||
MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_DECL (mem),
|
||||
MEM_OFFSET (mem), MEM_SIZE (mem), align);
|
||||
}
|
||||
|
||||
/* Return a memory reference like MEMREF, but with its mode changed to MODE
|
||||
and its address changed to ADDR. (VOIDmode means don't change the mode.
|
||||
NULL for ADDR means don't change the address.) VALIDATE is nonzero if the
|
||||
returned memory location is required to be valid. The memory
|
||||
attributes are not changed. */
|
||||
|
||||
static rtx
|
||||
change_address_1 (memref, mode, addr, validate)
|
||||
rtx memref;
|
||||
enum machine_mode mode;
|
||||
@ -1768,21 +1795,42 @@ change_address_1 (memref, mode, addr, validate)
|
||||
return new;
|
||||
}
|
||||
|
||||
/* Return a memory reference like MEMREF, but with its mode changed
|
||||
to MODE and its address offset by OFFSET bytes. */
|
||||
/* Like change_address_1 with VALIDATE nonzero, but we are not saying in what
|
||||
way we are changing MEMREF, so we only preserve the alias set. */
|
||||
|
||||
rtx
|
||||
adjust_address (memref, mode, offset)
|
||||
change_address (memref, mode, addr)
|
||||
rtx memref;
|
||||
enum machine_mode mode;
|
||||
rtx addr;
|
||||
{
|
||||
rtx new = change_address_1 (memref, mode, addr, 1);
|
||||
enum machine_mode mmode = GET_MODE (new);
|
||||
|
||||
MEM_ATTRS (new)
|
||||
= get_mem_attrs (MEM_ALIAS_SET (memref), 0, 0,
|
||||
mmode == BLKmode ? 0 : GEN_INT (GET_MODE_SIZE (mmode)),
|
||||
(mmode == BLKmode ? 1
|
||||
: GET_MODE_ALIGNMENT (mmode) / BITS_PER_UNIT));
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
/* Return a memory reference like MEMREF, but with its mode changed
|
||||
to MODE and its address offset by OFFSET bytes. If VALIDATE is
|
||||
nonzero, the memory address is forced to be valid. */
|
||||
|
||||
rtx
|
||||
adjust_address_1 (memref, mode, offset, validate)
|
||||
rtx memref;
|
||||
enum machine_mode mode;
|
||||
HOST_WIDE_INT offset;
|
||||
int validate;
|
||||
{
|
||||
/* For now, this is just a wrapper for change_address, but eventually
|
||||
will do memref tracking. */
|
||||
rtx addr = XEXP (memref, 0);
|
||||
|
||||
/* ??? Prefer to create garbage instead of creating shared rtl. */
|
||||
addr = copy_rtx (addr);
|
||||
rtx new;
|
||||
rtx memoffset = MEM_OFFSET (memref);
|
||||
unsigned int memalign = MEM_ALIGN (memref);
|
||||
|
||||
/* If MEMREF is a LO_SUM and the offset is within the alignment of the
|
||||
object, we can merge it into the LO_SUM. */
|
||||
@ -1792,36 +1840,36 @@ adjust_address (memref, mode, offset)
|
||||
< GET_MODE_ALIGNMENT (GET_MODE (memref)) / BITS_PER_UNIT)
|
||||
addr = gen_rtx_LO_SUM (Pmode, XEXP (addr, 0),
|
||||
plus_constant (XEXP (addr, 1), offset));
|
||||
else if (offset == 0)
|
||||
/* ??? Prefer to create garbage instead of creating shared rtl. */
|
||||
addr = copy_rtx (addr);
|
||||
else
|
||||
addr = plus_constant (addr, offset);
|
||||
|
||||
return change_address (memref, mode, addr);
|
||||
}
|
||||
new = change_address_1 (memref, mode, addr, validate);
|
||||
|
||||
/* Likewise, but the reference is not required to be valid. */
|
||||
/* Compute the new values of the memory attributes due to this adjustment.
|
||||
We add the offsets and update the alignment. */
|
||||
if (memoffset)
|
||||
memoffset = GEN_INT (offset + INTVAL (memoffset));
|
||||
|
||||
rtx
|
||||
adjust_address_nv (memref, mode, offset)
|
||||
rtx memref;
|
||||
enum machine_mode mode;
|
||||
HOST_WIDE_INT offset;
|
||||
{
|
||||
/* For now, this is just a wrapper for change_address, but eventually
|
||||
will do memref tracking. */
|
||||
rtx addr = XEXP (memref, 0);
|
||||
/* If the offset is negative, don't try to update the alignment. If it's
|
||||
zero, the alignment hasn't changed. Otherwise, the known alignment may
|
||||
be less strict. */
|
||||
if (offset < 0)
|
||||
memalign = 1;
|
||||
|
||||
/* If MEMREF is a LO_SUM and the offset is within the size of the
|
||||
object, we can merge it into the LO_SUM. */
|
||||
if (GET_MODE (memref) != BLKmode && GET_CODE (addr) == LO_SUM
|
||||
&& offset >= 0
|
||||
&& (unsigned HOST_WIDE_INT) offset
|
||||
< GET_MODE_ALIGNMENT (GET_MODE (memref)) / BITS_PER_UNIT)
|
||||
addr = gen_rtx_LO_SUM (mode, XEXP (addr, 0),
|
||||
plus_constant (XEXP (addr, 1), offset));
|
||||
else
|
||||
addr = plus_constant (addr, offset);
|
||||
while (offset > 0 && (offset % memalign) != 0)
|
||||
memalign >>= 1;
|
||||
|
||||
return change_address_1 (memref, mode, addr, 0);
|
||||
MEM_ATTRS (new)
|
||||
= get_mem_attrs (MEM_ALIAS_SET (memref), MEM_DECL (memref), memoffset,
|
||||
mode == BLKmode
|
||||
? 0 : GEN_INT (GET_MODE_SIZE (mode)), memalign);
|
||||
|
||||
/* At some point, we should validate that this offset is within the object,
|
||||
if all the appropriate values are known. */
|
||||
return new;
|
||||
}
|
||||
|
||||
/* Return a memory reference like MEMREF, but with its address changed to
|
||||
@ -1834,10 +1882,11 @@ replace_equiv_address (memref, addr)
|
||||
rtx memref;
|
||||
rtx addr;
|
||||
{
|
||||
/* For now, this is just a wrapper for change_address, but eventually
|
||||
will do memref tracking. */
|
||||
return change_address (memref, VOIDmode, addr);
|
||||
/* change_address_1 copies the memory attribute structure without change
|
||||
and that's exactly what we want here. */
|
||||
return change_address_1 (memref, VOIDmode, addr, 1);
|
||||
}
|
||||
|
||||
/* Likewise, but the reference is not required to be valid. */
|
||||
|
||||
rtx
|
||||
@ -1845,8 +1894,6 @@ replace_equiv_address_nv (memref, addr)
|
||||
rtx memref;
|
||||
rtx addr;
|
||||
{
|
||||
/* For now, this is just a wrapper for change_address, but eventually
|
||||
will do memref tracking. */
|
||||
return change_address_1 (memref, VOIDmode, addr, 0);
|
||||
}
|
||||
|
||||
|
21
gcc/expr.c
21
gcc/expr.c
@ -5403,6 +5403,7 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
|
||||
tree offset = size_zero_node;
|
||||
tree bit_offset = bitsize_zero_node;
|
||||
unsigned int alignment = BIGGEST_ALIGNMENT;
|
||||
tree placeholder_ptr = 0;
|
||||
tree tem;
|
||||
|
||||
/* First get the mode, signedness, and size. We do this from just the
|
||||
@ -5500,6 +5501,11 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
|
||||
unit_size));
|
||||
}
|
||||
|
||||
else if (TREE_CODE (exp) == PLACEHOLDER_EXPR)
|
||||
{
|
||||
exp = find_placeholder (exp, &placeholder_ptr);
|
||||
continue;
|
||||
}
|
||||
else if (TREE_CODE (exp) != NON_LVALUE_EXPR
|
||||
&& ! ((TREE_CODE (exp) == NOP_EXPR
|
||||
|| TREE_CODE (exp) == CONVERT_EXPR)
|
||||
@ -5961,10 +5967,11 @@ check_max_integer_computation_mode (exp)
|
||||
|
||||
/* Return an object on the placeholder list that matches EXP, a
|
||||
PLACEHOLDER_EXPR. An object "matches" if it is of the type of the
|
||||
PLACEHOLDER_EXPR or a pointer type to it. For further information,
|
||||
see tree.def. If no such object is found, abort. If PLIST is nonzero,
|
||||
it is a location into which a pointer into the placeholder list at
|
||||
which the object is found is placed. */
|
||||
PLACEHOLDER_EXPR or a pointer type to it. For further information, see
|
||||
tree.def. If no such object is found, abort. If PLIST is nonzero, it is
|
||||
a location which initially points to a starting location in the
|
||||
placeholder list (zero means start of the list) and where a pointer into
|
||||
the placeholder list at which the object is found is placed. */
|
||||
|
||||
tree
|
||||
find_placeholder (exp, plist)
|
||||
@ -5974,7 +5981,9 @@ find_placeholder (exp, plist)
|
||||
tree type = TREE_TYPE (exp);
|
||||
tree placeholder_expr;
|
||||
|
||||
for (placeholder_expr = placeholder_list; placeholder_expr != 0;
|
||||
for (placeholder_expr
|
||||
= plist && *plist ? TREE_CHAIN (*plist) : placeholder_list;
|
||||
placeholder_expr != 0;
|
||||
placeholder_expr = TREE_CHAIN (placeholder_expr))
|
||||
{
|
||||
tree need_type = TYPE_MAIN_VARIANT (type);
|
||||
@ -6550,7 +6559,7 @@ expand_expr (exp, target, tmode, modifier)
|
||||
case PLACEHOLDER_EXPR:
|
||||
{
|
||||
tree old_list = placeholder_list;
|
||||
tree placeholder_expr;
|
||||
tree placeholder_expr = 0;
|
||||
|
||||
exp = find_placeholder (exp, &placeholder_expr);
|
||||
placeholder_list = TREE_CHAIN (placeholder_expr);
|
||||
|
30
gcc/expr.h
30
gcc/expr.h
@ -500,10 +500,11 @@ extern rtx force_operand PARAMS ((rtx, rtx));
|
||||
|
||||
/* Return an object on the placeholder list that matches EXP, a
|
||||
PLACEHOLDER_EXPR. An object "matches" if it is of the type of the
|
||||
PLACEHOLDER_EXPR or a pointer type to it. For further information,
|
||||
see tree.def. If no such object is found, abort. If PLIST is nonzero,
|
||||
it is a location into which a pointer into the placeholder list at
|
||||
which the object is found is placed. */
|
||||
PLACEHOLDER_EXPR or a pointer type to it. For further information, see
|
||||
tree.def. If no such object is found, abort. If PLIST is nonzero, it is
|
||||
a location which initially points to a starting location in the
|
||||
placeholder list (zero means start of the list) and where a pointer into
|
||||
the placeholder list at which the object is found is placed. */
|
||||
extern tree find_placeholder PARAMS ((tree, tree *));
|
||||
|
||||
/* Generate code for computing expression EXP.
|
||||
@ -611,23 +612,26 @@ extern rtx memory_address_noforce PARAMS ((enum machine_mode, rtx));
|
||||
/* Set the alias set of MEM to SET. */
|
||||
extern void set_mem_alias_set PARAMS ((rtx, HOST_WIDE_INT));
|
||||
|
||||
/* Set the alignment of MEM to ALIGN. */
|
||||
extern void set_mem_align PARAMS ((rtx, unsigned int));
|
||||
|
||||
/* Return a memory reference like MEMREF, but with its mode changed
|
||||
to MODE and its address changed to ADDR.
|
||||
(VOIDmode means don't change the mode.
|
||||
NULL for ADDR means don't change the address.)
|
||||
VALIDATE is nonzero if the returned memory location is required to be
|
||||
valid. */
|
||||
extern rtx change_address_1 PARAMS ((rtx, enum machine_mode, rtx, int));
|
||||
|
||||
#define change_address(MEMREF, MODE, ADDR) \
|
||||
change_address_1 (MEMREF, MODE, ADDR, 1)
|
||||
NULL for ADDR means don't change the address.) */
|
||||
extern rtx change_address PARAMS ((rtx, enum machine_mode, rtx));
|
||||
|
||||
/* Return a memory reference like MEMREF, but with its mode changed
|
||||
to MODE and its address offset by OFFSET bytes. */
|
||||
extern rtx adjust_address PARAMS ((rtx, enum machine_mode, HOST_WIDE_INT));
|
||||
#define adjust_address(MEMREF, MODE, OFFSET) \
|
||||
adjust_address_1 (MEMREF, MODE, OFFSET, 1)
|
||||
|
||||
/* Likewise, but the reference is not required to be valid. */
|
||||
extern rtx adjust_address_nv PARAMS ((rtx, enum machine_mode, HOST_WIDE_INT));
|
||||
#define adjust_address_nv(MEMREF, MODE, OFFSET) \
|
||||
adjust_address_1 (MEMREF, MODE, OFFSET, 0)
|
||||
|
||||
extern rtx adjust_address_1 PARAMS ((rtx, enum machine_mode, HOST_WIDE_INT,
|
||||
int));
|
||||
|
||||
/* Return a memory reference like MEMREF, but with its address changed to
|
||||
ADDR. The caller is asserting that the actual piece of memory pointed
|
||||
|
@ -23,6 +23,11 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "rtl.h"
|
||||
|
||||
/* We don't want the tree code checking code for the access to the
|
||||
DECL_NAME to be included in the gen* programs. */
|
||||
#undef ENABLE_TREE_CHECKING
|
||||
#include "tree.h"
|
||||
#include "real.h"
|
||||
#include "flags.h"
|
||||
#include "hard-reg-set.h"
|
||||
@ -446,8 +451,30 @@ print_rtx (in_rtx)
|
||||
switch (GET_CODE (in_rtx))
|
||||
{
|
||||
case MEM:
|
||||
fputc (' ', outfile);
|
||||
fputs (" [", outfile);
|
||||
fprintf (outfile, HOST_WIDE_INT_PRINT_DEC, MEM_ALIAS_SET (in_rtx));
|
||||
if (MEM_DECL (in_rtx) && DECL_NAME (MEM_DECL (in_rtx)))
|
||||
fprintf (outfile, " %s",
|
||||
IDENTIFIER_POINTER (DECL_NAME (MEM_DECL (in_rtx))));
|
||||
|
||||
if (MEM_OFFSET (in_rtx))
|
||||
{
|
||||
fputc ('+', outfile);
|
||||
fprintf (outfile, HOST_WIDE_INT_PRINT_DEC,
|
||||
INTVAL (MEM_OFFSET (in_rtx)));
|
||||
}
|
||||
|
||||
if (MEM_SIZE (in_rtx))
|
||||
{
|
||||
fputs (" S", outfile);
|
||||
fprintf (outfile, HOST_WIDE_INT_PRINT_DEC,
|
||||
INTVAL (MEM_SIZE (in_rtx)));
|
||||
}
|
||||
|
||||
if (MEM_ALIGN (in_rtx) != 1)
|
||||
fprintf (outfile, " A%u", MEM_ALIGN (in_rtx));
|
||||
|
||||
fputc (']', outfile);
|
||||
break;
|
||||
|
||||
#if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT && MAX_LONG_DOUBLE_TYPE_SIZE == 64
|
||||
|
Loading…
Reference in New Issue
Block a user