invoke.texi (-fstrict-aliasing): Document.
* invoke.texi (-fstrict-aliasing): Document. * rtl.texi (MEM_ALIAS_SET): Document. * flags.h (flag_strict_aliasing): Declare. * toplev.c (flag_strict_aliasing): Define. (f_options): Add -strict-aliasing. (main): Set flag_strict_aliasing if -O2 or higher. * tree.h (tree_type): Add alias_set field. (TYPE_ALIAS_SET): New macro. (TYPE_ALIAS_SET_KNOWN_P): Likewise. (get_alias_set): Declare. * tree.c (lang_get_alias_set): Define. (make_node): Initialize TYPE_ALIAS_SET. (get_alias_set): New function. * print-tree.c (print_node): Dump the alias set for a type. * c-tree.h (c_get_alias_set): Declare. * c-common.c (c_get_alias_set): New function. * c-decl.c (init_decl_processing): Set lang_get_alias_set. * expr.c (protect_from_queue): Propogage alias sets. (expand_assignment): Calculate alias set for new MEMs. (expand_expr): Likewise. * function.c (put_var_into_stack): Likewise. (put_reg_into_stack): Likewise. (gen_mem_addressof): Likewise. (assign_parms): Likewise. * stmt.c (expand_decl): Likewise. * varasm.c (make_decl_rtl): Eliminate redundant clearing of DECL_RTL. Calculate alias set for new MEMs. * rtl.def (REG): Add dummy operand. (MEM): Add extra operand to store the MEM_ALIAS_SET. * rtl.h (MEM_ALIAS_SET): New macro. (gen_rtx_MEM): Declare. * emit-rtl.c (gen_rtx_MEM): New function. * gengenrtl.c (sepcial_rtx): Make MEMs special. * alias.c (CHECK_ALIAS_SETS_FOR_CONSISTENCY): New macro. (DIFFERENT_ALIAS_SETS_P): Likewise. (canon_rtx): Propogate the alias set to the new MEM. (true_dependence): Check the alias sets. (anti_dependence): Likewise. (output_dependence): Likewise. * explow.c (stabilize): Progoate alias sets. * integrate.c (copy_rtx_and_substitute): Likewise. * final.c (alter_subreg): Make sure not to leave MEM_IN_STRUCT_P in an unpredictable state. Propogate alias sets. * reload1.c (reload): Clear MEM_ALIAS_SET for new MEMs about which we have no alias information. From-SVN: r20719
This commit is contained in:
parent
9c606f693d
commit
41472af877
24 changed files with 369 additions and 18 deletions
|
@ -1,3 +1,57 @@
|
|||
Thu Jun 25 15:08:16 1998 Mark Mitchell <mark@markmitchell.com>
|
||||
|
||||
* invoke.texi (-fstrict-aliasing): Document.
|
||||
* rtl.texi (MEM_ALIAS_SET): Document.
|
||||
|
||||
* flags.h (flag_strict_aliasing): Declare.
|
||||
* toplev.c (flag_strict_aliasing): Define.
|
||||
(f_options): Add -strict-aliasing.
|
||||
(main): Set flag_strict_aliasing if -O2 or higher.
|
||||
|
||||
* tree.h (tree_type): Add alias_set field.
|
||||
(TYPE_ALIAS_SET): New macro.
|
||||
(TYPE_ALIAS_SET_KNOWN_P): Likewise.
|
||||
(get_alias_set): Declare.
|
||||
* tree.c (lang_get_alias_set): Define.
|
||||
(make_node): Initialize TYPE_ALIAS_SET.
|
||||
(get_alias_set): New function.
|
||||
* print-tree.c (print_node): Dump the alias set for a type.
|
||||
|
||||
* c-tree.h (c_get_alias_set): Declare.
|
||||
* c-common.c (c_get_alias_set): New function.
|
||||
* c-decl.c (init_decl_processing): Set lang_get_alias_set.
|
||||
|
||||
* expr.c (protect_from_queue): Propogage alias sets.
|
||||
(expand_assignment): Calculate alias set for new MEMs.
|
||||
(expand_expr): Likewise.
|
||||
* function.c (put_var_into_stack): Likewise.
|
||||
(put_reg_into_stack): Likewise.
|
||||
(gen_mem_addressof): Likewise.
|
||||
(assign_parms): Likewise.
|
||||
* stmt.c (expand_decl): Likewise.
|
||||
* varasm.c (make_decl_rtl): Eliminate redundant clearing of
|
||||
DECL_RTL. Calculate alias set for new MEMs.
|
||||
|
||||
* rtl.def (REG): Add dummy operand.
|
||||
(MEM): Add extra operand to store the MEM_ALIAS_SET.
|
||||
* rtl.h (MEM_ALIAS_SET): New macro.
|
||||
(gen_rtx_MEM): Declare.
|
||||
* emit-rtl.c (gen_rtx_MEM): New function.
|
||||
* gengenrtl.c (sepcial_rtx): Make MEMs special.
|
||||
|
||||
* alias.c (CHECK_ALIAS_SETS_FOR_CONSISTENCY): New macro.
|
||||
(DIFFERENT_ALIAS_SETS_P): Likewise.
|
||||
(canon_rtx): Propogate the alias set to the new MEM.
|
||||
(true_dependence): Check the alias sets.
|
||||
(anti_dependence): Likewise.
|
||||
(output_dependence): Likewise.
|
||||
* explow.c (stabilize): Progoate alias sets.
|
||||
* integrate.c (copy_rtx_and_substitute): Likewise.
|
||||
* final.c (alter_subreg): Make sure not to leave MEM_IN_STRUCT_P
|
||||
in an unpredictable state. Propogate alias sets.
|
||||
* reload1.c (reload): Clear MEM_ALIAS_SET for new MEMs about which
|
||||
we have no alias information.
|
||||
|
||||
Thu Jun 25 16:59:18 EDT 1998 Andrew MacLeod <amacleod@cygnus.com>
|
||||
|
||||
* except.h (CATCH_ALL_TYPE): Definition moved to eh-common.h.
|
||||
|
|
32
gcc/alias.c
32
gcc/alias.c
|
@ -42,6 +42,28 @@ static rtx find_base_value PROTO((rtx));
|
|||
|
||||
#define SIZE_FOR_MODE(X) (GET_MODE_SIZE (GET_MODE (X)))
|
||||
|
||||
/* Perform a basic sanity check. Namely, that there are
|
||||
no alias sets if we're not doing strict aliasing. This helps
|
||||
to catch bugs whereby someone uses PUT_CODE, but doesn't clear
|
||||
MEM_ALIAS_SET, or where a MEM is allocated in some way other
|
||||
than by the use of gen_rtx_MEM, and the MEM_ALIAS_SET is not
|
||||
cleared. */
|
||||
#ifdef ENABLE_CHECKING
|
||||
#define CHECK_ALIAS_SETS_FOR_CONSISTENCY(MEM1, MEM2) \
|
||||
(!flag_strict_aliasing \
|
||||
&& (MEM_ALIAS_SET (MEM1) || MEM_ALIAS_SET (MEM2)) \
|
||||
? (abort (), 0) : 0)
|
||||
#else
|
||||
#define CHECK_ALIAS_SETS_FOR_CONSISTENCY(MEM1, MEM2) 0
|
||||
#endif
|
||||
|
||||
/* Returns nonzero if MEM1 and MEM2 do not alias because they are in
|
||||
different alias sets. */
|
||||
#define DIFFERENT_ALIAS_SETS_P(MEM1, MEM2) \
|
||||
(CHECK_ALIAS_SETS_FOR_CONSISTENCY(MEM1, MEM2), \
|
||||
MEM_ALIAS_SET (MEM1) && MEM_ALIAS_SET (MEM2) \
|
||||
&& MEM_ALIAS_SET (MEM1) != MEM_ALIAS_SET (MEM2))
|
||||
|
||||
/* Cap the number of passes we make over the insns propagating alias
|
||||
information through set chains.
|
||||
|
||||
|
@ -372,6 +394,7 @@ canon_rtx (x)
|
|||
MEM_VOLATILE_P (new) = MEM_VOLATILE_P (x);
|
||||
RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (x);
|
||||
MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (x);
|
||||
MEM_ALIAS_SET (new) = MEM_ALIAS_SET (x);
|
||||
x = new;
|
||||
}
|
||||
}
|
||||
|
@ -874,6 +897,9 @@ true_dependence (mem, mem_mode, x, varies)
|
|||
if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
|
||||
return 1;
|
||||
|
||||
if (DIFFERENT_ALIAS_SETS_P (x, mem))
|
||||
return 0;
|
||||
|
||||
/* If X is an unchanging read, then it can't possibly conflict with any
|
||||
non-unchanging store. It may conflict with an unchanging write though,
|
||||
because there may be a single store to this address to initialize it.
|
||||
|
@ -947,6 +973,9 @@ anti_dependence (mem, x)
|
|||
x = canon_rtx (x);
|
||||
mem = canon_rtx (mem);
|
||||
|
||||
if (DIFFERENT_ALIAS_SETS_P (x, mem))
|
||||
return 0;
|
||||
|
||||
x_addr = XEXP (x, 0);
|
||||
mem_addr = XEXP (mem, 0);
|
||||
|
||||
|
@ -978,6 +1007,9 @@ output_dependence (mem, x)
|
|||
x = canon_rtx (x);
|
||||
mem = canon_rtx (mem);
|
||||
|
||||
if (DIFFERENT_ALIAS_SETS_P (x, mem))
|
||||
return 0;
|
||||
|
||||
return (memrefs_conflict_p (SIZE_FOR_MODE (mem), XEXP (mem, 0),
|
||||
SIZE_FOR_MODE (x), XEXP (x, 0), 0)
|
||||
&& ! (MEM_IN_STRUCT_P (mem) && rtx_addr_varies_p (mem)
|
||||
|
|
|
@ -2880,3 +2880,90 @@ c_build_type_variant (type, constp, volatilep)
|
|||
TYPE_DOMAIN (type));
|
||||
return build_type_variant (type, constp, volatilep);
|
||||
}
|
||||
|
||||
/* Return the typed-based alias set for T, which may be an expression
|
||||
or a type. */
|
||||
|
||||
int
|
||||
c_get_alias_set (t)
|
||||
tree t;
|
||||
{
|
||||
static int next_set = 0;
|
||||
tree type;
|
||||
|
||||
if (t == error_mark_node)
|
||||
return 0;
|
||||
|
||||
type = (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
|
||||
? t : TREE_TYPE (t);
|
||||
|
||||
if (type == error_mark_node)
|
||||
return 0;
|
||||
|
||||
if (TYPE_ALIAS_SET_KNOWN_P (type))
|
||||
/* If we've already calculated the value, just return it. */
|
||||
return TYPE_ALIAS_SET (type);
|
||||
|
||||
if (TREE_CODE (t) == BIT_FIELD_REF)
|
||||
/* Perhaps reads and writes to this piece of data alias fields
|
||||
neighboring the bitfield. Perhaps that's impossible. For now,
|
||||
let's just assume that bitfields can alias everything, which is
|
||||
the conservative assumption. */
|
||||
return 0;
|
||||
if (TREE_CODE (t) == COMPONENT_REF
|
||||
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == UNION_TYPE)
|
||||
/* Permit type-punning when accessing a union, provided the
|
||||
access is directly through the union. For example, this code does
|
||||
not permit taking the address of a union member and then
|
||||
storing through it. Even the type-punning allowed here is a
|
||||
GCC extension, albeit a common and useful one; the C standard
|
||||
says that such accesses have implementation-defined behavior. */
|
||||
return 0;
|
||||
else if (TYPE_MAIN_VARIANT (type) != type)
|
||||
{
|
||||
/* The C standard specifically allows aliasing between
|
||||
cv-qualified variants of types. */
|
||||
TYPE_ALIAS_SET (type) = c_get_alias_set (TYPE_MAIN_VARIANT (type));
|
||||
return TYPE_ALIAS_SET (type);
|
||||
}
|
||||
else if (TREE_CODE (type) == INTEGER_TYPE)
|
||||
{
|
||||
tree signed_variant;
|
||||
|
||||
/* The C standard specifically allows aliasing between signed and
|
||||
unsigned variants of the same type. We treat the signed
|
||||
variant as canonical. */
|
||||
signed_variant = signed_type (type);
|
||||
|
||||
if (signed_variant != type)
|
||||
{
|
||||
TYPE_ALIAS_SET (type) = c_get_alias_set (signed_variant);
|
||||
return TYPE_ALIAS_SET (type);
|
||||
}
|
||||
else if (signed_variant == signed_char_type_node)
|
||||
/* The C standard guarantess that any object may be accessed
|
||||
via an lvalue that has character type. We don't have to
|
||||
check for unsigned_char_type_node or char_type_node because
|
||||
we are specifically looking at the signed variant. */
|
||||
{
|
||||
TYPE_ALIAS_SET (type) = 0;
|
||||
return TYPE_ALIAS_SET (type);
|
||||
}
|
||||
}
|
||||
else if (TREE_CODE (type) == RECORD_TYPE
|
||||
|| TREE_CODE (type) == UNION_TYPE)
|
||||
{
|
||||
/* If TYPE is a struct or union type then we're reading or
|
||||
writing an entire struct. Thus, we don't know anything about
|
||||
aliasing. (In theory, such an access can only alias objects
|
||||
whose type is the same as one of the fields, recursively, but
|
||||
we don't yet make any use of that information.) */
|
||||
TYPE_ALIAS_SET (type) = 0;
|
||||
return TYPE_ALIAS_SET (type);
|
||||
}
|
||||
|
||||
/* TYPE is something we haven't seen before. Put it in a new alias
|
||||
set. */
|
||||
TYPE_ALIAS_SET (type) = ++next_set;
|
||||
return TYPE_ALIAS_SET (type);
|
||||
}
|
||||
|
|
|
@ -3513,6 +3513,8 @@ init_decl_processing ()
|
|||
init_iterators ();
|
||||
|
||||
incomplete_decl_finalize_hook = finish_incomplete_decl;
|
||||
|
||||
lang_get_alias_set = &c_get_alias_set;
|
||||
}
|
||||
|
||||
/* Return a definition for a builtin function named NAME and whose data type
|
||||
|
|
|
@ -164,6 +164,7 @@ extern void declare_function_name PROTO((void));
|
|||
extern void decl_attributes PROTO((tree, tree, tree));
|
||||
extern void init_function_format_info PROTO((void));
|
||||
extern void check_function_format PROTO((tree, tree, tree));
|
||||
extern int c_get_alias_set PROTO((tree));
|
||||
/* Print an error message for invalid operands to arith operation CODE.
|
||||
NOP_EXPR is used as a special case (see truthvalue_conversion). */
|
||||
extern void binary_op_error PROTO((enum tree_code));
|
||||
|
|
|
@ -301,6 +301,20 @@ gen_rtx_REG (mode, regno)
|
|||
return gen_rtx_raw_REG (mode, regno);
|
||||
}
|
||||
|
||||
rtx
|
||||
gen_rtx_MEM (mode, addr)
|
||||
enum machine_mode mode;
|
||||
rtx addr;
|
||||
{
|
||||
rtx rt = gen_rtx_raw_MEM (mode, addr);
|
||||
|
||||
/* This field is not cleared by the mere allocation of the rtx, so
|
||||
we clear it here. */
|
||||
MEM_ALIAS_SET (rt) = 0;
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
/* rtx gen_rtx (code, mode, [element1, ..., elementn])
|
||||
**
|
||||
** This routine generates an RTX of the size specified by
|
||||
|
|
|
@ -592,6 +592,11 @@ stabilize (x)
|
|||
MEM_IN_STRUCT_P (mem) = MEM_IN_STRUCT_P (x) || GET_CODE (addr) == PLUS;
|
||||
RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (x);
|
||||
MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (x);
|
||||
|
||||
/* Since the new MEM is just like the old X, it can alias only
|
||||
the things that X could. */
|
||||
MEM_ALIAS_SET (mem) = MEM_ALIAS_SET (x);
|
||||
|
||||
return mem;
|
||||
}
|
||||
return x;
|
||||
|
|
12
gcc/expr.c
12
gcc/expr.c
|
@ -415,6 +415,7 @@ protect_from_queue (x, modify)
|
|||
MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (x);
|
||||
RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (x);
|
||||
MEM_VOLATILE_P (new) = MEM_VOLATILE_P (x);
|
||||
MEM_ALIAS_SET (new) = MEM_ALIAS_SET (x);
|
||||
|
||||
if (QUEUED_INSN (y))
|
||||
{
|
||||
|
@ -3063,7 +3064,11 @@ expand_assignment (to, from, want_value, suggest_reg)
|
|||
Don't re-expand if it was expanded already (in COMPONENT_REF case). */
|
||||
|
||||
if (to_rtx == 0)
|
||||
to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_WO);
|
||||
{
|
||||
to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_WO);
|
||||
if (GET_CODE (to_rtx) == MEM)
|
||||
MEM_ALIAS_SET (to_rtx) = get_alias_set (to);
|
||||
}
|
||||
|
||||
/* Don't move directly into a return register. */
|
||||
if (TREE_CODE (to) == RESULT_DECL && GET_CODE (to_rtx) == REG)
|
||||
|
@ -5719,6 +5724,7 @@ expand_expr (exp, target, tmode, modifier)
|
|||
&& AGGREGATE_TYPE_P (TREE_TYPE (exp2))))
|
||||
MEM_IN_STRUCT_P (temp) = 1;
|
||||
MEM_VOLATILE_P (temp) = TREE_THIS_VOLATILE (exp) | flag_volatile;
|
||||
MEM_ALIAS_SET (temp) = get_alias_set (exp);
|
||||
|
||||
/* It is incorrect to set RTX_UNCHANGING_P from TREE_READONLY
|
||||
here, because, in C and C++, the fact that a location is accessed
|
||||
|
@ -6094,6 +6100,10 @@ expand_expr (exp, target, tmode, modifier)
|
|||
op0 = change_address (op0, mode1,
|
||||
plus_constant (XEXP (op0, 0),
|
||||
(bitpos / BITS_PER_UNIT)));
|
||||
|
||||
if (GET_CODE (op0) == MEM)
|
||||
MEM_ALIAS_SET (op0) = get_alias_set (exp);
|
||||
|
||||
if (GET_CODE (XEXP (op0, 0)) == REG)
|
||||
mark_reg_pointer (XEXP (op0, 0), alignment);
|
||||
|
||||
|
|
|
@ -3020,6 +3020,8 @@ alter_subreg (x)
|
|||
- MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (y))));
|
||||
PUT_CODE (x, MEM);
|
||||
MEM_VOLATILE_P (x) = MEM_VOLATILE_P (y);
|
||||
MEM_IN_STRUCT_P (x) = MEM_IN_STRUCT_P (y);
|
||||
MEM_ALIAS_SET (x) = MEM_ALIAS_SET (y);
|
||||
XEXP (x, 0) = plus_constant (XEXP (y, 0), offset);
|
||||
}
|
||||
|
||||
|
|
|
@ -432,6 +432,12 @@ extern int flag_pack_struct;
|
|||
The value is ignored if flag_alias_check is 0. */
|
||||
extern int flag_argument_noalias;
|
||||
|
||||
/* Nonzero if we should do (language-dependent) alias analysis.
|
||||
Typically, this analysis will assume that expressions of certain
|
||||
types do not alias expressions of certain other types. Only used
|
||||
if alias analysis (in general) is enabled. */
|
||||
extern int flag_strict_aliasing;
|
||||
|
||||
/* Emit code to check for stack overflow; also may cause large objects
|
||||
to be allocated dynamically. */
|
||||
extern int flag_stack_check;
|
||||
|
|
|
@ -1466,6 +1466,7 @@ put_var_into_stack (decl)
|
|||
/* Change the CONCAT into a combined MEM for both parts. */
|
||||
PUT_CODE (reg, MEM);
|
||||
MEM_VOLATILE_P (reg) = MEM_VOLATILE_P (XEXP (reg, 0));
|
||||
MEM_ALIAS_SET (reg) = get_alias_set (decl);
|
||||
|
||||
/* The two parts are in memory order already.
|
||||
Use the lower parts address as ours. */
|
||||
|
@ -1538,6 +1539,7 @@ put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p,
|
|||
case it was set for other reasons. For instance, it is set for
|
||||
__builtin_va_alist. */
|
||||
MEM_IN_STRUCT_P (reg) = AGGREGATE_TYPE_P (type) | MEM_IN_STRUCT_P (new);
|
||||
MEM_ALIAS_SET (reg) = get_alias_set (type);
|
||||
|
||||
/* Now make sure that all refs to the variable, previously made
|
||||
when it was a register, are fixed up to be valid again. */
|
||||
|
@ -2735,6 +2737,7 @@ gen_mem_addressof (reg, decl)
|
|||
PUT_MODE (reg, DECL_MODE (decl));
|
||||
MEM_VOLATILE_P (reg) = TREE_SIDE_EFFECTS (decl);
|
||||
MEM_IN_STRUCT_P (reg) = AGGREGATE_TYPE_P (type);
|
||||
MEM_ALIAS_SET (reg) = get_alias_set (decl);
|
||||
|
||||
if (TREE_USED (decl) || DECL_INITIAL (decl) != 0)
|
||||
fixup_var_refs (reg, GET_MODE (reg), TREE_UNSIGNED (type));
|
||||
|
@ -3908,6 +3911,7 @@ assign_parms (fndecl, second_time)
|
|||
is readonly. */
|
||||
MEM_IN_STRUCT_P (stack_parm) = aggregate;
|
||||
RTX_UNCHANGING_P (stack_parm) = TREE_READONLY (parm);
|
||||
MEM_ALIAS_SET (stack_parm) = get_alias_set (parm);
|
||||
}
|
||||
|
||||
/* If this parameter was passed both in registers and in the stack,
|
||||
|
|
|
@ -129,7 +129,8 @@ special_rtx (idx)
|
|||
int idx;
|
||||
{
|
||||
return (strcmp (defs[idx].enumname, "CONST_INT") == 0
|
||||
|| strcmp (defs[idx].enumname, "REG") == 0);
|
||||
|| strcmp (defs[idx].enumname, "REG") == 0
|
||||
|| strcmp (defs[idx].enumname, "MEM") == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -2688,6 +2688,7 @@ copy_rtx_and_substitute (orig, map)
|
|||
XEXP (copy, 0) = copy_rtx_and_substitute (XEXP (orig, 0), map);
|
||||
MEM_IN_STRUCT_P (copy) = MEM_IN_STRUCT_P (orig);
|
||||
MEM_VOLATILE_P (copy) = MEM_VOLATILE_P (orig);
|
||||
MEM_ALIAS_SET (copy) = MEM_ALIAS_SET (orig);
|
||||
|
||||
/* If doing function inlining, this MEM might not be const in the
|
||||
function that it is being inlined into, and thus may not be
|
||||
|
|
|
@ -156,7 +156,7 @@ in the following sections.
|
|||
-frerun-cse-after-loop -frerun-loop-opt -fschedule-insns
|
||||
-fschedule-insns2 -fstrength-reduce -fthread-jumps
|
||||
-funroll-all-loops -funroll-loops
|
||||
-fmove-all-movables -freduce-all-givs
|
||||
-fmove-all-movables -freduce-all-givs -fstrict-aliasing
|
||||
-O -O0 -O1 -O2 -O3 -Os
|
||||
@end smallexample
|
||||
|
||||
|
@ -2419,6 +2419,57 @@ Some machines only support 2 operands per instruction. On such
|
|||
machines, GNU CC might have to do extra copies. The @samp{-fregmove}
|
||||
option overrides the default for the machine to do the copy before
|
||||
register allocation.
|
||||
|
||||
@item -fstrict-aliasing
|
||||
Allows the compiler to assume the strictest aliasing rules applicable to
|
||||
the language being compiled. For C (and C++), this activates
|
||||
optimizations based on the type of expressions. In particular, an
|
||||
object of one type is assumed never to reside at the same address as an
|
||||
object of a different type, unless the types are almost the same. For
|
||||
example, an @code{unsigned int} can alias an @code{int}, but not a
|
||||
@code{void*} or a @code{double}. A character type may alias any other
|
||||
type.
|
||||
|
||||
Pay special attention to code like this:
|
||||
@example
|
||||
union a_union @{
|
||||
int i;
|
||||
double d;
|
||||
@};
|
||||
|
||||
int f() @{
|
||||
a_union t;
|
||||
t.d = 3.0;
|
||||
return t.i;
|
||||
@}
|
||||
@end example
|
||||
The practice of reading from a different union member than the one most
|
||||
recently written to (called ``type-punning'') is common. Even with
|
||||
@samp{-fstrict-aliasing}, type-punning is allowed, provided the memory
|
||||
is accessed through the union type. So, the code above will work as
|
||||
expected. However, this code might not:
|
||||
@example
|
||||
int f() @{
|
||||
a_union t;
|
||||
int* ip;
|
||||
t.d = 3.0;
|
||||
ip = &t.i;
|
||||
return *ip;
|
||||
@}
|
||||
@end example
|
||||
|
||||
This option is not enabled by default at any optimization level because
|
||||
it is new and has yet to be subjected to thorough testing. You may
|
||||
of course enable it manually with @samp{-fstrict-aliasing}.
|
||||
|
||||
@ifset INTERNALS
|
||||
Every language that wishes to perform language-specific alias analysis
|
||||
should define a function that computes, given an @code{tree}
|
||||
node, an alias set for the node. Nodes in different alias sets are not
|
||||
allowed to alias. For an example, see the C front-end function
|
||||
@code{c_get_alias_set}.
|
||||
@end ifset
|
||||
|
||||
@end table
|
||||
|
||||
@node Preprocessor Options
|
||||
|
|
|
@ -479,6 +479,7 @@ print_node (file, prefix, node, indent)
|
|||
|
||||
fprintf (file, " align %d", TYPE_ALIGN (node));
|
||||
fprintf (file, " symtab %d", TYPE_SYMTAB_ADDRESS (node));
|
||||
fprintf (file, " alias set %d", TYPE_ALIAS_SET (node));
|
||||
|
||||
print_node (file, "attributes", TYPE_ATTRIBUTES (node), indent + 4);
|
||||
|
||||
|
|
|
@ -2095,6 +2095,9 @@ reload (first, global, dumpfile)
|
|||
XEXP (reg, 0) = addr;
|
||||
REG_USERVAR_P (reg) = 0;
|
||||
MEM_IN_STRUCT_P (reg) = in_struct;
|
||||
/* We have no alias information about this newly created
|
||||
MEM. */
|
||||
MEM_ALIAS_SET (reg) = 0;
|
||||
PUT_CODE (reg, MEM);
|
||||
}
|
||||
else if (reg_equiv_mem[i])
|
||||
|
|
22
gcc/rtl.def
22
gcc/rtl.def
|
@ -537,10 +537,16 @@ DEF_RTL_EXPR(CONST, "const", "e", 'o')
|
|||
by a SET whose first operand is (PC). */
|
||||
DEF_RTL_EXPR(PC, "pc", "", 'o')
|
||||
|
||||
/* A register. The "operand" is the register number, accessed
|
||||
with the REGNO macro. If this number is less than FIRST_PSEUDO_REGISTER
|
||||
than a hardware register is being referred to. */
|
||||
DEF_RTL_EXPR(REG, "reg", "i", 'o')
|
||||
/* A register. The "operand" is the register number, accessed with
|
||||
the REGNO macro. If this number is less than FIRST_PSEUDO_REGISTER
|
||||
than a hardware register is being referred to. The second operand
|
||||
doesn't really exist. Unfortunately, however, the compiler
|
||||
implicitly assumes that a REG can be transformed in place into a
|
||||
MEM, and therefore that a REG is at least as big as a MEM. To
|
||||
avoid this memory overhead, which is likely to be substantial,
|
||||
search for uses of PUT_CODE that turn REGs into MEMs, and fix them
|
||||
somehow. Then, the trailing `0' can be removed here. */
|
||||
DEF_RTL_EXPR(REG, "reg", "i0", 'o')
|
||||
|
||||
/* A scratch register. This represents a register used only within a
|
||||
single insn. It will be turned into a REG during register allocation
|
||||
|
@ -578,9 +584,11 @@ DEF_RTL_EXPR(STRICT_LOW_PART, "strict_low_part", "e", 'x')
|
|||
in DECL_RTLs and during RTL generation, but not in the insn chain. */
|
||||
DEF_RTL_EXPR(CONCAT, "concat", "ee", 'o')
|
||||
|
||||
/* A memory location; operand is the address.
|
||||
Can be nested inside a VOLATILE. */
|
||||
DEF_RTL_EXPR(MEM, "mem", "e", 'o')
|
||||
/* A memory location; operand is the address. Can be nested inside a
|
||||
VOLATILE. The second operand is the alias set to which this MEM
|
||||
belongs. We use `0' instead of `i' for this field so that the
|
||||
field need not be specified in machine descriptions. */
|
||||
DEF_RTL_EXPR(MEM, "mem", "e0", 'o')
|
||||
|
||||
/* Reference to an assembler label in the code for this function.
|
||||
The operand is a CODE_LABEL found in the insn chain.
|
||||
|
|
17
gcc/rtl.h
17
gcc/rtl.h
|
@ -561,6 +561,17 @@ extern char *note_insn_name[];
|
|||
/* For a MEM rtx, 1 if it refers to a field of an aggregate. */
|
||||
#define MEM_IN_STRUCT_P(RTX) ((RTX)->in_struct)
|
||||
|
||||
/* For a MEM rtx, the alias set. If 0, this MEM is not in any alias
|
||||
set, and may alias anything. Otherwise, the MEM can only alias
|
||||
MEMs in the same alias set. This value is set in a
|
||||
language-dependent manner in the front-end, and should not be
|
||||
altered in the back-end. These set numbers are tested for zero,
|
||||
and compared for equality; they have no other significance. In
|
||||
some front-ends, these numbers may correspond in some way to types,
|
||||
or other language-level entities, but they need not, and the
|
||||
back-end makes no such assumptions. */
|
||||
#define MEM_ALIAS_SET(RTX) (XINT (RTX, 1))
|
||||
|
||||
/* For a LABEL_REF, 1 means that this reference is to a label outside the
|
||||
loop containing the reference. */
|
||||
#define LABEL_OUTSIDE_LOOP_P(RTX) ((RTX)->in_struct)
|
||||
|
@ -1057,11 +1068,13 @@ extern rtx static_chain_incoming_rtx;
|
|||
#include "genrtl.h"
|
||||
#endif
|
||||
|
||||
/* There are two RTL codes that require special attention; the generation
|
||||
functions included above do the raw handling. */
|
||||
/* There are some RTL codes that require special attention; the
|
||||
generation functions included above do the raw handling. If you
|
||||
add to this list, modify special_rtx in gengenrtl.c as well. */
|
||||
|
||||
extern rtx gen_rtx_CONST_INT PROTO((enum machine_mode, HOST_WIDE_INT));
|
||||
extern rtx gen_rtx_REG PROTO((enum machine_mode, int));
|
||||
extern rtx gen_rtx_MEM PROTO((enum machine_mode, rtx));
|
||||
|
||||
/* We need the cast here to ensure that we get the same result both with
|
||||
and without prototypes. */
|
||||
|
|
15
gcc/rtl.texi
15
gcc/rtl.texi
|
@ -287,9 +287,9 @@ to access them.
|
|||
@section Flags in an RTL Expression
|
||||
@cindex flags in RTL expression
|
||||
|
||||
RTL expressions contain several flags (one-bit bitfields) that are used
|
||||
in certain types of expression. Most often they are accessed with the
|
||||
following macros:
|
||||
RTL expressions contain several flags (one-bit bitfields) and other
|
||||
values that are used in certain types of expression. Most often they
|
||||
are accessed with the following macros:
|
||||
|
||||
@table @code
|
||||
@findex MEM_VOLATILE_P
|
||||
|
@ -310,6 +310,15 @@ structure, union or array, or to a component of one. Zero for
|
|||
references to a scalar variable or through a pointer to a scalar.
|
||||
Stored in the @code{in_struct} field and printed as @samp{/s}.
|
||||
|
||||
@findex MEM_ALIAS_SET
|
||||
@item MEM_ALIAS_SET (@var{x})
|
||||
In @code{mem} expressions, the alias set to which @var{x} belongs. If
|
||||
zero, @var{x} is not in any alias set, and may alias anything. If
|
||||
nonzero, @var{x} may only alias objects in the same alias set. This
|
||||
value is set (in a language-specific manner) by the front-end. This
|
||||
field is not a bit-field; it is in an integer, found as the second
|
||||
argument to the @code{mem}.
|
||||
|
||||
@findex REG_LOOP_TEST_P
|
||||
@cindex @code{reg} and @samp{/s}
|
||||
@cindex @code{in_struct}, in @code{reg}
|
||||
|
|
|
@ -3178,6 +3178,8 @@ expand_decl (decl)
|
|||
if (flag_float_store && TREE_CODE (type) == REAL_TYPE)
|
||||
MEM_VOLATILE_P (DECL_RTL (decl)) = 1;
|
||||
#endif
|
||||
|
||||
MEM_ALIAS_SET (DECL_RTL (decl)) = get_alias_set (decl);
|
||||
}
|
||||
else
|
||||
/* Dynamic-size object: must push space on the stack. */
|
||||
|
|
10
gcc/toplev.c
10
gcc/toplev.c
|
@ -711,6 +711,12 @@ int flag_regmove = 0;
|
|||
This defaults to 0 for C. */
|
||||
int flag_argument_noalias = 0;
|
||||
|
||||
/* Nonzero if we should do (language-dependent) alias analysis.
|
||||
Typically, this analysis will assume that expressions of certain
|
||||
types do not alias expressions of certain other types. Only used
|
||||
if alias analysis (in general) is enabled. */
|
||||
int flag_strict_aliasing = 0;
|
||||
|
||||
/* Table of language-independent -f options.
|
||||
STRING is the option name. VARIABLE is the address of the variable.
|
||||
ON_VALUE is the value to store in VARIABLE
|
||||
|
@ -782,6 +788,7 @@ struct { char *string; int *variable; int on_value;} f_options[] =
|
|||
{"argument-alias", &flag_argument_noalias, 0},
|
||||
{"argument-noalias", &flag_argument_noalias, 1},
|
||||
{"argument-noalias-global", &flag_argument_noalias, 2},
|
||||
{"strict-aliasing", &flag_strict_aliasing, 1},
|
||||
{"check-memory-usage", &flag_check_memory_usage, 1},
|
||||
{"prefix-function-name", &flag_prefix_function_name, 1}
|
||||
};
|
||||
|
@ -3839,6 +3846,9 @@ main (argc, argv, envp)
|
|||
flag_schedule_insns_after_reload = 1;
|
||||
#endif
|
||||
flag_regmove = 1;
|
||||
/* We don't set flag_strict_aliasing here because we're still
|
||||
testing the functionality. After it has been tested, it
|
||||
should be turned on here. */
|
||||
}
|
||||
|
||||
if (optimize >= 3)
|
||||
|
|
21
gcc/tree.c
21
gcc/tree.c
|
@ -261,6 +261,10 @@ static int next_decl_uid;
|
|||
/* Unique id for next type created. */
|
||||
static int next_type_uid = 1;
|
||||
|
||||
/* The language-specific function for alias analysis. If NULL, the
|
||||
language does not do any special alias analysis. */
|
||||
int (*lang_get_alias_set) PROTO((tree));
|
||||
|
||||
/* Here is how primitive or already-canonicalized types' hash
|
||||
codes are made. */
|
||||
#define TYPE_HASH(TYPE) ((unsigned long) (TYPE) & 0777777)
|
||||
|
@ -1112,6 +1116,9 @@ make_node (code)
|
|||
#ifdef SET_DEFAULT_TYPE_ATTRIBUTES
|
||||
SET_DEFAULT_TYPE_ATTRIBUTES (t);
|
||||
#endif
|
||||
/* Note that we have not yet computed the alias set for this
|
||||
type. */
|
||||
TYPE_ALIAS_SET (t) = -1;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
|
@ -5019,3 +5026,17 @@ expr_check (node, ignored, file, line, nofatal)
|
|||
return node;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return the alias set for T, which may be either a type or an
|
||||
expression. */
|
||||
|
||||
int get_alias_set (t)
|
||||
tree t;
|
||||
{
|
||||
if (!flag_strict_aliasing || !lang_get_alias_set)
|
||||
/* If we're not doing any lanaguage-specific alias analysis, just
|
||||
assume everything aliases everything else. */
|
||||
return 0;
|
||||
else
|
||||
return (*lang_get_alias_set) (t);
|
||||
}
|
||||
|
|
15
gcc/tree.h
15
gcc/tree.h
|
@ -776,6 +776,18 @@ struct tree_block
|
|||
#define TYPE_OBSTACK(NODE) (TYPE_CHECK (NODE)->type.obstack)
|
||||
#define TYPE_LANG_SPECIFIC(NODE) (TYPE_CHECK (NODE)->type.lang_specific)
|
||||
|
||||
/* The (language-specific) typed-based alias set for this type.
|
||||
Objects whose TYPE_ALIAS_SETs are different cannot alias each
|
||||
other. If the TYPE_ALIAS_SET is -1, no alias set has yet been
|
||||
assigned to this type. If the TYPE_ALIAS_SET is 0, objects of this
|
||||
type can alias objects of any type. */
|
||||
#define TYPE_ALIAS_SET(NODE) (TYPE_CHECK (NODE)->type.alias_set)
|
||||
|
||||
/* Nonzero iff the typed-based alias set for this type has been
|
||||
calculated. */
|
||||
#define TYPE_ALIAS_SET_KNOWN_P(NODE) \
|
||||
(TYPE_CHECK (NODE)->type.alias_set != -1)
|
||||
|
||||
/* A TREE_LIST of IDENTIFIER nodes of the attributes that apply
|
||||
to this type. */
|
||||
#define TYPE_ATTRIBUTES(NODE) (TYPE_CHECK (NODE)->type.attributes)
|
||||
|
@ -870,6 +882,7 @@ struct tree_type
|
|||
union tree_node *noncopied_parts;
|
||||
union tree_node *context;
|
||||
struct obstack *obstack;
|
||||
int alias_set;
|
||||
/* Points to a structure whose details depend on the language in use. */
|
||||
struct lang_type *lang_specific;
|
||||
};
|
||||
|
@ -1811,6 +1824,8 @@ extern tree get_file_function_name PROTO((int));
|
|||
extern tree get_set_constructor_bits PROTO((tree, char *, int));
|
||||
extern tree get_set_constructor_bytes PROTO((tree,
|
||||
unsigned char *, int));
|
||||
extern int get_alias_set PROTO((tree));
|
||||
extern int (*lang_get_alias_set) PROTO((tree));
|
||||
|
||||
/* In stmt.c */
|
||||
|
||||
|
|
|
@ -662,8 +662,6 @@ make_decl_rtl (decl, asmspec, top_level)
|
|||
same DECL node. Don't discard the RTL already made. */
|
||||
if (DECL_RTL (decl) == 0)
|
||||
{
|
||||
DECL_RTL (decl) = 0;
|
||||
|
||||
/* First detect errors in declaring global registers. */
|
||||
if (TREE_CODE (decl) != FUNCTION_DECL
|
||||
&& DECL_REGISTER (decl) && reg_number == -1)
|
||||
|
@ -767,7 +765,8 @@ make_decl_rtl (decl, asmspec, top_level)
|
|||
|
||||
DECL_RTL (decl) = gen_rtx_MEM (DECL_MODE (decl),
|
||||
gen_rtx_SYMBOL_REF (Pmode, name));
|
||||
|
||||
MEM_ALIAS_SET (DECL_RTL (decl)) = get_alias_set (decl);
|
||||
|
||||
/* If this variable is to be treated as volatile, show its
|
||||
tree node has side effects. If it has side effects, either
|
||||
because of this test or from TREE_THIS_VOLATILE also
|
||||
|
|
Loading…
Add table
Reference in a new issue