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>
|
2001-10-17 Richard Henderson <rth@redhat.com>
|
||||||
|
|
||||||
* config/alpha/alpha.c (direct_call_operand): Don't fall off end.
|
* 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
|
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)
|
$(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 \
|
print-rtl.o : print-rtl.c $(GCONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) \
|
||||||
$(BASIC_BLOCK_H)
|
hard-reg-set.h $(BASIC_BLOCK_H)
|
||||||
$(CC) -c $(ALL_CFLAGS) -DGENERATOR_FILE $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
|
$(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
|
rtlanal.o : rtlanal.c $(CONFIG_H) $(SYSTEM_H) toplev.h $(RTL_H) hard-reg-set.h
|
||||||
|
111
gcc/alias.c
111
gcc/alias.c
@ -458,7 +458,6 @@ HOST_WIDE_INT
|
|||||||
get_alias_set (t)
|
get_alias_set (t)
|
||||||
tree t;
|
tree t;
|
||||||
{
|
{
|
||||||
tree orig_t;
|
|
||||||
HOST_WIDE_INT set;
|
HOST_WIDE_INT set;
|
||||||
|
|
||||||
/* If we're not doing any alias analysis, just assume everything
|
/* If we're not doing any alias analysis, just assume everything
|
||||||
@ -473,12 +472,74 @@ get_alias_set (t)
|
|||||||
language-specific routine may make mutually-recursive calls to each other
|
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
|
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
|
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
|
aren't types. */
|
||||||
actual object. Also replace PLACEHOLDER_EXPRs and pick up the outermost
|
|
||||||
object that we could have a pointer to. */
|
|
||||||
if (! TYPE_P (t))
|
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)
|
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)))))
|
== TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 0)))))
|
||||||
@ -492,44 +553,22 @@ get_alias_set (t)
|
|||||||
return set;
|
return set;
|
||||||
|
|
||||||
if (TREE_CODE (t) == PLACEHOLDER_EXPR)
|
if (TREE_CODE (t) == PLACEHOLDER_EXPR)
|
||||||
t = find_placeholder (t, 0);
|
t = find_placeholder (t, &placeholder_ptr);
|
||||||
else
|
else
|
||||||
t = TREE_OPERAND (t, 0);
|
t = TREE_OPERAND (t, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now give the language a chance to do something but record what we
|
/* Give the language another chance to do something. */
|
||||||
gave it this time. */
|
|
||||||
orig_t = t;
|
|
||||||
if ((set = lang_get_alias_set (t)) != -1)
|
if ((set = lang_get_alias_set (t)) != -1)
|
||||||
return set;
|
return set;
|
||||||
|
|
||||||
/* Check for accesses through restrict-qualified pointers. */
|
/* If we've already determined the alias set for a decl, just return
|
||||||
if (TREE_CODE (t) == INDIRECT_REF)
|
it. This is necessary for C++ anonymous unions, whose component
|
||||||
{
|
variables don't look like union members (boo!). */
|
||||||
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 (TREE_CODE (t) == VAR_DECL
|
if (TREE_CODE (t) == VAR_DECL
|
||||||
&& DECL_RTL_SET_P (t) && GET_CODE (DECL_RTL (t)) == MEM)
|
&& DECL_RTL_SET_P (t) && GET_CODE (DECL_RTL (t)) == MEM)
|
||||||
return MEM_ALIAS_SET (DECL_RTL (t));
|
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. */
|
/* Now all we care about is the type. */
|
||||||
t = TREE_TYPE (t);
|
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 qualifiers don't affect the alias set, so get the main
|
||||||
variant. If this is a type with a known alias set, return it. */
|
variant. If this is a type with a known alias set, return it. */
|
||||||
t = TYPE_MAIN_VARIANT (t);
|
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);
|
return TYPE_ALIAS_SET (t);
|
||||||
|
|
||||||
/* See if the language has special handling for this type. */
|
/* See if the language has special handling for this type. */
|
||||||
if ((set = lang_get_alias_set (t)) != -1)
|
if ((set = lang_get_alias_set (t)) != -1)
|
||||||
{
|
return set;
|
||||||
/* If the alias set is now known, we are done. */
|
|
||||||
if (TYPE_ALIAS_SET_KNOWN_P (t))
|
|
||||||
return TYPE_ALIAS_SET (t);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* There are no objects of FUNCTION_TYPE, so there's no point in
|
/* 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
|
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 make_call_insn_raw PARAMS ((rtx));
|
||||||
static rtx find_line_note PARAMS ((rtx));
|
static rtx find_line_note PARAMS ((rtx));
|
||||||
static void mark_sequence_stack PARAMS ((struct sequence_stack *));
|
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_rtl_1 PARAMS ((rtx));
|
||||||
static void unshare_all_decls PARAMS ((tree));
|
static void unshare_all_decls PARAMS ((tree));
|
||||||
static void reset_used_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);
|
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
|
/* 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
|
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
|
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))
|
if (DECL_P (t) && ref == DECL_RTL_IF_SET (t))
|
||||||
abort ();
|
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));
|
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_VOLATILE_P (ref) = TYPE_VOLATILE (type);
|
||||||
MEM_IN_STRUCT_P (ref) = AGGREGATE_TYPE_P (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))
|
if (objectp && ! AGGREGATE_TYPE_P (type))
|
||||||
MEM_SCALAR_P (ref) = 1;
|
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. */
|
to deduce some more information about the expression. */
|
||||||
if (TYPE_P (t))
|
if (TYPE_P (t))
|
||||||
return;
|
return;
|
||||||
@ -1686,17 +1694,27 @@ set_mem_attributes (ref, t, objectp)
|
|||||||
if (TREE_THIS_VOLATILE (t))
|
if (TREE_THIS_VOLATILE (t))
|
||||||
MEM_VOLATILE_P (ref) = 1;
|
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.
|
/* Now remove any NOPs: they don't change what the underlying object is.
|
||||||
Likewise for SAVE_EXPR. */
|
Likewise for SAVE_EXPR. */
|
||||||
while (TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR
|
while (TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR
|
||||||
|| TREE_CODE (t) == NON_LVALUE_EXPR || TREE_CODE (t) == SAVE_EXPR)
|
|| TREE_CODE (t) == NON_LVALUE_EXPR || TREE_CODE (t) == SAVE_EXPR)
|
||||||
t = TREE_OPERAND (t, 0);
|
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,
|
/* 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,
|
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. */
|
this is part of an aggregate. Otherwise we don't know. */
|
||||||
@ -1715,7 +1733,6 @@ set_mem_alias_set (mem, set)
|
|||||||
rtx mem;
|
rtx mem;
|
||||||
HOST_WIDE_INT set;
|
HOST_WIDE_INT set;
|
||||||
{
|
{
|
||||||
/* It would be nice to enable this check, but we can't quite yet. */
|
|
||||||
#ifdef ENABLE_CHECKING
|
#ifdef ENABLE_CHECKING
|
||||||
/* If the new and old alias sets don't conflict, something is wrong. */
|
/* If the new and old alias sets don't conflict, something is wrong. */
|
||||||
if (!alias_sets_conflict_p (set, MEM_ALIAS_SET (mem)))
|
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_ATTRS (mem) = get_mem_attrs (set, MEM_DECL (mem), MEM_OFFSET (mem),
|
||||||
MEM_SIZE (mem), MEM_ALIGN (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)
|
change_address_1 (memref, mode, addr, validate)
|
||||||
rtx memref;
|
rtx memref;
|
||||||
enum machine_mode mode;
|
enum machine_mode mode;
|
||||||
@ -1768,21 +1795,42 @@ change_address_1 (memref, mode, addr, validate)
|
|||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return a memory reference like MEMREF, but with its mode changed
|
/* Like change_address_1 with VALIDATE nonzero, but we are not saying in what
|
||||||
to MODE and its address offset by OFFSET bytes. */
|
way we are changing MEMREF, so we only preserve the alias set. */
|
||||||
|
|
||||||
rtx
|
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;
|
rtx memref;
|
||||||
enum machine_mode mode;
|
enum machine_mode mode;
|
||||||
HOST_WIDE_INT offset;
|
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);
|
rtx addr = XEXP (memref, 0);
|
||||||
|
rtx new;
|
||||||
/* ??? Prefer to create garbage instead of creating shared rtl. */
|
rtx memoffset = MEM_OFFSET (memref);
|
||||||
addr = copy_rtx (addr);
|
unsigned int memalign = MEM_ALIGN (memref);
|
||||||
|
|
||||||
/* If MEMREF is a LO_SUM and the offset is within the alignment of the
|
/* If MEMREF is a LO_SUM and the offset is within the alignment of the
|
||||||
object, we can merge it into the LO_SUM. */
|
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)
|
< GET_MODE_ALIGNMENT (GET_MODE (memref)) / BITS_PER_UNIT)
|
||||||
addr = gen_rtx_LO_SUM (Pmode, XEXP (addr, 0),
|
addr = gen_rtx_LO_SUM (Pmode, XEXP (addr, 0),
|
||||||
plus_constant (XEXP (addr, 1), offset));
|
plus_constant (XEXP (addr, 1), offset));
|
||||||
|
else if (offset == 0)
|
||||||
|
/* ??? Prefer to create garbage instead of creating shared rtl. */
|
||||||
|
addr = copy_rtx (addr);
|
||||||
else
|
else
|
||||||
addr = plus_constant (addr, offset);
|
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
|
/* If the offset is negative, don't try to update the alignment. If it's
|
||||||
adjust_address_nv (memref, mode, offset)
|
zero, the alignment hasn't changed. Otherwise, the known alignment may
|
||||||
rtx memref;
|
be less strict. */
|
||||||
enum machine_mode mode;
|
if (offset < 0)
|
||||||
HOST_WIDE_INT offset;
|
memalign = 1;
|
||||||
{
|
|
||||||
/* For now, this is just a wrapper for change_address, but eventually
|
|
||||||
will do memref tracking. */
|
|
||||||
rtx addr = XEXP (memref, 0);
|
|
||||||
|
|
||||||
/* If MEMREF is a LO_SUM and the offset is within the size of the
|
while (offset > 0 && (offset % memalign) != 0)
|
||||||
object, we can merge it into the LO_SUM. */
|
memalign >>= 1;
|
||||||
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);
|
|
||||||
|
|
||||||
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
|
/* Return a memory reference like MEMREF, but with its address changed to
|
||||||
@ -1834,10 +1882,11 @@ replace_equiv_address (memref, addr)
|
|||||||
rtx memref;
|
rtx memref;
|
||||||
rtx addr;
|
rtx addr;
|
||||||
{
|
{
|
||||||
/* For now, this is just a wrapper for change_address, but eventually
|
/* change_address_1 copies the memory attribute structure without change
|
||||||
will do memref tracking. */
|
and that's exactly what we want here. */
|
||||||
return change_address (memref, VOIDmode, addr);
|
return change_address_1 (memref, VOIDmode, addr, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Likewise, but the reference is not required to be valid. */
|
/* Likewise, but the reference is not required to be valid. */
|
||||||
|
|
||||||
rtx
|
rtx
|
||||||
@ -1845,8 +1894,6 @@ replace_equiv_address_nv (memref, addr)
|
|||||||
rtx memref;
|
rtx memref;
|
||||||
rtx addr;
|
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);
|
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 offset = size_zero_node;
|
||||||
tree bit_offset = bitsize_zero_node;
|
tree bit_offset = bitsize_zero_node;
|
||||||
unsigned int alignment = BIGGEST_ALIGNMENT;
|
unsigned int alignment = BIGGEST_ALIGNMENT;
|
||||||
|
tree placeholder_ptr = 0;
|
||||||
tree tem;
|
tree tem;
|
||||||
|
|
||||||
/* First get the mode, signedness, and size. We do this from just the
|
/* 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));
|
unit_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (TREE_CODE (exp) == PLACEHOLDER_EXPR)
|
||||||
|
{
|
||||||
|
exp = find_placeholder (exp, &placeholder_ptr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
else if (TREE_CODE (exp) != NON_LVALUE_EXPR
|
else if (TREE_CODE (exp) != NON_LVALUE_EXPR
|
||||||
&& ! ((TREE_CODE (exp) == NOP_EXPR
|
&& ! ((TREE_CODE (exp) == NOP_EXPR
|
||||||
|| TREE_CODE (exp) == CONVERT_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
|
/* 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. An object "matches" if it is of the type of the
|
||||||
PLACEHOLDER_EXPR or a pointer type to it. For further information,
|
PLACEHOLDER_EXPR or a pointer type to it. For further information, see
|
||||||
see tree.def. If no such object is found, abort. If PLIST is nonzero,
|
tree.def. If no such object is found, abort. If PLIST is nonzero, it is
|
||||||
it is a location into which a pointer into the placeholder list at
|
a location which initially points to a starting location in the
|
||||||
which the object is found is placed. */
|
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
|
tree
|
||||||
find_placeholder (exp, plist)
|
find_placeholder (exp, plist)
|
||||||
@ -5974,7 +5981,9 @@ find_placeholder (exp, plist)
|
|||||||
tree type = TREE_TYPE (exp);
|
tree type = TREE_TYPE (exp);
|
||||||
tree placeholder_expr;
|
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))
|
placeholder_expr = TREE_CHAIN (placeholder_expr))
|
||||||
{
|
{
|
||||||
tree need_type = TYPE_MAIN_VARIANT (type);
|
tree need_type = TYPE_MAIN_VARIANT (type);
|
||||||
@ -6550,7 +6559,7 @@ expand_expr (exp, target, tmode, modifier)
|
|||||||
case PLACEHOLDER_EXPR:
|
case PLACEHOLDER_EXPR:
|
||||||
{
|
{
|
||||||
tree old_list = placeholder_list;
|
tree old_list = placeholder_list;
|
||||||
tree placeholder_expr;
|
tree placeholder_expr = 0;
|
||||||
|
|
||||||
exp = find_placeholder (exp, &placeholder_expr);
|
exp = find_placeholder (exp, &placeholder_expr);
|
||||||
placeholder_list = TREE_CHAIN (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
|
/* 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. An object "matches" if it is of the type of the
|
||||||
PLACEHOLDER_EXPR or a pointer type to it. For further information,
|
PLACEHOLDER_EXPR or a pointer type to it. For further information, see
|
||||||
see tree.def. If no such object is found, abort. If PLIST is nonzero,
|
tree.def. If no such object is found, abort. If PLIST is nonzero, it is
|
||||||
it is a location into which a pointer into the placeholder list at
|
a location which initially points to a starting location in the
|
||||||
which the object is found is placed. */
|
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 *));
|
extern tree find_placeholder PARAMS ((tree, tree *));
|
||||||
|
|
||||||
/* Generate code for computing expression EXP.
|
/* 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. */
|
/* Set the alias set of MEM to SET. */
|
||||||
extern void set_mem_alias_set PARAMS ((rtx, HOST_WIDE_INT));
|
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
|
/* Return a memory reference like MEMREF, but with its mode changed
|
||||||
to MODE and its address changed to ADDR.
|
to MODE and its address changed to ADDR.
|
||||||
(VOIDmode means don't change the mode.
|
(VOIDmode means don't change the mode.
|
||||||
NULL for ADDR means don't change the address.)
|
NULL for ADDR means don't change the address.) */
|
||||||
VALIDATE is nonzero if the returned memory location is required to be
|
extern rtx change_address PARAMS ((rtx, enum machine_mode, rtx));
|
||||||
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)
|
|
||||||
|
|
||||||
/* Return a memory reference like MEMREF, but with its mode changed
|
/* Return a memory reference like MEMREF, but with its mode changed
|
||||||
to MODE and its address offset by OFFSET bytes. */
|
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. */
|
/* 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
|
/* Return a memory reference like MEMREF, but with its address changed to
|
||||||
ADDR. The caller is asserting that the actual piece of memory pointed
|
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 "config.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "rtl.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 "real.h"
|
||||||
#include "flags.h"
|
#include "flags.h"
|
||||||
#include "hard-reg-set.h"
|
#include "hard-reg-set.h"
|
||||||
@ -446,8 +451,30 @@ print_rtx (in_rtx)
|
|||||||
switch (GET_CODE (in_rtx))
|
switch (GET_CODE (in_rtx))
|
||||||
{
|
{
|
||||||
case MEM:
|
case MEM:
|
||||||
fputc (' ', outfile);
|
fputs (" [", outfile);
|
||||||
fprintf (outfile, HOST_WIDE_INT_PRINT_DEC, MEM_ALIAS_SET (in_rtx));
|
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;
|
break;
|
||||||
|
|
||||||
#if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT && MAX_LONG_DOUBLE_TYPE_SIZE == 64
|
#if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT && MAX_LONG_DOUBLE_TYPE_SIZE == 64
|
||||||
|
Loading…
Reference in New Issue
Block a user