From 41472af8777035219decfe1cb4742ce2b3ed8e38 Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Thu, 25 Jun 1998 15:14:41 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 54 ++++++++++++++++++++++++++++++ gcc/alias.c | 32 ++++++++++++++++++ gcc/c-common.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/c-decl.c | 2 ++ gcc/c-tree.h | 1 + gcc/emit-rtl.c | 14 ++++++++ gcc/explow.c | 5 +++ gcc/expr.c | 12 ++++++- gcc/final.c | 2 ++ gcc/flags.h | 6 ++++ gcc/function.c | 4 +++ gcc/gengenrtl.c | 3 +- gcc/integrate.c | 1 + gcc/invoke.texi | 53 ++++++++++++++++++++++++++++- gcc/print-tree.c | 1 + gcc/reload1.c | 3 ++ gcc/rtl.def | 22 ++++++++---- gcc/rtl.h | 17 ++++++++-- gcc/rtl.texi | 15 +++++++-- gcc/stmt.c | 2 ++ gcc/toplev.c | 10 ++++++ gcc/tree.c | 21 ++++++++++++ gcc/tree.h | 15 +++++++++ gcc/varasm.c | 5 ++- 24 files changed, 369 insertions(+), 18 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7360bff192f..b9ada6d0851 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,57 @@ +Thu Jun 25 15:08:16 1998 Mark Mitchell + + * 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 * except.h (CATCH_ALL_TYPE): Definition moved to eh-common.h. diff --git a/gcc/alias.c b/gcc/alias.c index 99df4fa8ccf..ab65bc4d8ea 100644 --- a/gcc/alias.c +++ b/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) diff --git a/gcc/c-common.c b/gcc/c-common.c index 9a8d0731bdd..245fedb97be 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -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); +} diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 51a18c5a0dd..15eb740b976 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -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 diff --git a/gcc/c-tree.h b/gcc/c-tree.h index 6ec4f674e25..3a9f4f83b78 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -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)); diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index 854b9892e2b..8f1b50188bf 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -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 diff --git a/gcc/explow.c b/gcc/explow.c index 7c74d6a620f..cd50563be52 100644 --- a/gcc/explow.c +++ b/gcc/explow.c @@ -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; diff --git a/gcc/expr.c b/gcc/expr.c index 91134d393ca..bc19068afaa 100644 --- a/gcc/expr.c +++ b/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); diff --git a/gcc/final.c b/gcc/final.c index ca6c22037d8..794bedf70b1 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -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); } diff --git a/gcc/flags.h b/gcc/flags.h index 2b670054eb6..2b62325bb29 100644 --- a/gcc/flags.h +++ b/gcc/flags.h @@ -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; diff --git a/gcc/function.c b/gcc/function.c index f8e3cd40667..f3d33d0cc39 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -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, diff --git a/gcc/gengenrtl.c b/gcc/gengenrtl.c index a8daeae465b..ade07ff4b6c 100644 --- a/gcc/gengenrtl.c +++ b/gcc/gengenrtl.c @@ -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 diff --git a/gcc/integrate.c b/gcc/integrate.c index a7fb3d7eb8b..38a900a9768 100644 --- a/gcc/integrate.c +++ b/gcc/integrate.c @@ -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 diff --git a/gcc/invoke.texi b/gcc/invoke.texi index 56bdfdbae47..3bc197f9b66 100644 --- a/gcc/invoke.texi +++ b/gcc/invoke.texi @@ -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 diff --git a/gcc/print-tree.c b/gcc/print-tree.c index 6674a18aa8d..6163b1ff91c 100644 --- a/gcc/print-tree.c +++ b/gcc/print-tree.c @@ -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); diff --git a/gcc/reload1.c b/gcc/reload1.c index 9acf695679a..9601691f9f9 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -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]) diff --git a/gcc/rtl.def b/gcc/rtl.def index e219e87c042..a00d3f1d7c5 100644 --- a/gcc/rtl.def +++ b/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. diff --git a/gcc/rtl.h b/gcc/rtl.h index bee83bbc0d8..af85d823738 100644 --- a/gcc/rtl.h +++ b/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. */ diff --git a/gcc/rtl.texi b/gcc/rtl.texi index 0127fcea456..4d5139956dc 100644 --- a/gcc/rtl.texi +++ b/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} diff --git a/gcc/stmt.c b/gcc/stmt.c index feeea171693..43cf7f82ec2 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -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. */ diff --git a/gcc/toplev.c b/gcc/toplev.c index 42d3616e359..d51dc60eb95 100644 --- a/gcc/toplev.c +++ b/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) diff --git a/gcc/tree.c b/gcc/tree.c index baf4551cadd..de5a1791af1 100644 --- a/gcc/tree.c +++ b/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); +} diff --git a/gcc/tree.h b/gcc/tree.h index 62b31687490..be62730706b 100644 --- a/gcc/tree.h +++ b/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 */ diff --git a/gcc/varasm.c b/gcc/varasm.c index 760aa773e0c..4ba0e08d187 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.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