From: Jan Hubicka Date: Thu, 27 Jun 2019 12:07:43 +0000 (+0200) Subject: class.c (layout_class_type): Set TYPE_CXX_ODR_P for as-base type copy. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=a0276c00934da47fa511aa52e1973b68ffd8b2ab;p=gcc.git class.c (layout_class_type): Set TYPE_CXX_ODR_P for as-base type copy. * class.c (layout_class_type): Set TYPE_CXX_ODR_P for as-base type copy. * ipa-devirt.c (odr_type_d): Add tbaa_enabled flag. (add_type_duplicate): When odr hash is not allocated, to nothing. (odr_based_tbaa_p): New function. (set_type_canonical_for_odr_type): New function. * ipa-utils.h (enable_odr_based_tbaa, odr_based_tbaa_p, set_type_canonical_for_odr_type): New. * tree.c (gimple_canonical_types_compatible_p): ODR types with ODR based TBAA are not equivalent to non-ODR types. * lto-common.c: Include demangle.h and tree-pretty-print.h (type_streaming_finished): New static var. (gimple_register_canonical_type_1): Return updated hash; handle ODR types. (iterative_hash_canonical_type): Update use of gimple_register_canonical_type_1. * g++.dg/lto/alias-2_0.C: New testcase. * g++.dg/lto/alias-2_1.C: New testcase. From-SVN: r272749 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f536afb5ee3..948948f20fd 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2019-06-27 Jan Hubicka + + * ipa-devirt.c (odr_type_d): Add tbaa_enabled flag. + (add_type_duplicate): When odr hash is not allocated, to nothing. + (odr_based_tbaa_p): New function. + (set_type_canonical_for_odr_type): New function. + * ipa-utils.h (enable_odr_based_tbaa, odr_based_tbaa_p, + set_type_canonical_for_odr_type): New. + * tree.c (gimple_canonical_types_compatible_p): ODR types with + ODR based TBAA are not equivalent to non-ODR types. + 2019-06-27 Martin Liska PR tree-optimization/90974 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8314b9762f6..e6167651431 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2019-06-27 Jan Hubicka + + * class.c (layout_class_type): Set TYPE_CXX_ODR_P for as-base + type copy. + 2019-06-27 Martin Liska * class.c (adjust_clone_args): Remove obviously diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 18e7db08c8d..73291b341fe 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -6393,6 +6393,7 @@ layout_class_type (tree t, tree *virtuals_p) SET_TYPE_ALIGN (base_t, rli->record_align); TYPE_USER_ALIGN (base_t) = TYPE_USER_ALIGN (t); TYPE_TYPELESS_STORAGE (base_t) = TYPE_TYPELESS_STORAGE (t); + TYPE_CXX_ODR_P (base_t) = TYPE_CXX_ODR_P (t); /* Copy the non-static data members of T. This will include its direct non-virtual bases & vtable. */ diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c index a4c8b0de86f..252d9206181 100644 --- a/gcc/ipa-devirt.c +++ b/gcc/ipa-devirt.c @@ -213,6 +213,8 @@ struct GTY(()) odr_type_d bool odr_violated; /* Set when virtual table without RTTI previaled table with. */ bool rtti_broken; + /* Set when the canonical type is determined using the type name. */ + bool tbaa_enabled; }; /* Return TRUE if all derived types of T are known and thus @@ -1610,6 +1612,9 @@ add_type_duplicate (odr_type val, tree type) val->types_set->add (type); + if (!odr_hash) + return NULL; + gcc_checking_assert (can_be_name_hashed_p (type) && can_be_name_hashed_p (val->type)); @@ -1989,6 +1994,46 @@ prevailing_odr_type (tree type) return t->type; } +/* Set tbaa_enabled flag for TYPE. */ + +void +enable_odr_based_tbaa (tree type) +{ + odr_type t = get_odr_type (type, true); + t->tbaa_enabled = true; +} + +/* True if canonical type of TYPE is determined using ODR name. */ + +bool +odr_based_tbaa_p (const_tree type) +{ + if (!RECORD_OR_UNION_TYPE_P (type)) + return false; + odr_type t = get_odr_type (const_cast (type), false); + if (!t || !t->tbaa_enabled) + return false; + return true; +} + +/* Set TYPE_CANONICAL of type and all its variants and duplicates + to CANONICAL. */ + +void +set_type_canonical_for_odr_type (tree type, tree canonical) +{ + odr_type t = get_odr_type (type, false); + unsigned int i; + tree tt; + + for (tree t2 = t->type; t2; t2 = TYPE_NEXT_VARIANT (t2)) + TYPE_CANONICAL (t2) = canonical; + if (t->types) + FOR_EACH_VEC_ELT (*t->types, i, tt) + for (tree t2 = tt; t2; t2 = TYPE_NEXT_VARIANT (t2)) + TYPE_CANONICAL (t2) = canonical; +} + /* Return true if we reported some ODR violation on TYPE. */ bool diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h index 64974beb6d4..22e6970234a 100644 --- a/gcc/ipa-utils.h +++ b/gcc/ipa-utils.h @@ -93,6 +93,9 @@ bool odr_or_derived_type_p (const_tree t); bool odr_types_equivalent_p (tree type1, tree type2); bool odr_type_violation_reported_p (tree type); tree prevailing_odr_type (tree type); +void enable_odr_based_tbaa (tree type); +bool odr_based_tbaa_p (const_tree type); +void set_type_canonical_for_odr_type (tree type, tree canonical); /* Return vector containing possible targets of polymorphic call E. If COMPLETEP is non-NULL, store true if the list is complete. diff --git a/gcc/lto/lto-common.c b/gcc/lto/lto-common.c index 0d38ee6b57b..1275b673506 100644 --- a/gcc/lto/lto-common.c +++ b/gcc/lto/lto-common.c @@ -1,5 +1,5 @@ /* Top-level LTO routines. - Copyright (C) 2009-2018 Free Software Foundation, Inc. + Copyright (C) 2009-2019 Free Software Foundation, Inc. Contributed by CodeSourcery, Inc. This file is part of GCC. @@ -56,6 +56,11 @@ along with GCC; see the file COPYING3. If not see #include "attribs.h" #include "builtins.h" #include "lto-common.h" +#include "tree-pretty-print.h" + +/* True when no new types are going to be streamd from the global stream. */ + +static bool type_streaming_finished = false; GTY(()) tree first_personality_decl; @@ -217,9 +222,14 @@ static hash_map *canonical_type_hash_cache; static unsigned long num_canonical_type_hash_entries; static unsigned long num_canonical_type_hash_queries; +/* Types postponed for registration to the canonical type table. + During streaming we postpone all TYPE_CXX_ODR_P types so we can alter + decide whether there is conflict with non-ODR type or not. */ +static GTY(()) vec *types_to_register = NULL; + static void iterative_hash_canonical_type (tree type, inchash::hash &hstate); static hashval_t gimple_canonical_type_hash (const void *p); -static void gimple_register_canonical_type_1 (tree t, hashval_t hash); +static hashval_t gimple_register_canonical_type_1 (tree t, hashval_t hash); /* Returning a hash value for gimple type TYPE. @@ -357,9 +367,9 @@ iterative_hash_canonical_type (tree type, inchash::hash &hstate) optimal order. To avoid quadratic behavior also register the type here. */ v = hash_canonical_type (type); - gimple_register_canonical_type_1 (type, v); + v = gimple_register_canonical_type_1 (type, v); } - hstate.add_int (v); + hstate.merge_hash (v); } /* Returns the hash for a canonical type P. */ @@ -388,7 +398,7 @@ gimple_canonical_type_eq (const void *p1, const void *p2) /* Main worker for gimple_register_canonical_type. */ -static void +static hashval_t gimple_register_canonical_type_1 (tree t, hashval_t hash) { void **slot; @@ -397,6 +407,75 @@ gimple_register_canonical_type_1 (tree t, hashval_t hash) && type_with_alias_set_p (t) && canonical_type_used_p (t)); + /* ODR types for which there is no ODR violation and we did not record + structurally equivalent non-ODR type can be treated as unique by their + name. + + hash passed to gimple_register_canonical_type_1 is a structural hash + that we can use to lookup structurally equivalent non-ODR type. + In case we decide to treat type as unique ODR type we recompute hash based + on name and let TBAA machinery know about our decision. */ + if (RECORD_OR_UNION_TYPE_P (t) + && odr_type_p (t) && !odr_type_violation_reported_p (t)) + { + /* Here we rely on fact that all non-ODR types was inserted into + canonical type hash and thus we can safely detect conflicts between + ODR types and interoperable non-ODR types. */ + gcc_checking_assert (type_streaming_finished + && TYPE_MAIN_VARIANT (t) == t); + slot = htab_find_slot_with_hash (gimple_canonical_types, t, hash, + NO_INSERT); + if (slot && !TYPE_CXX_ODR_P (*(tree *)slot)) + { + tree nonodr = *(tree *)slot; + if (symtab->dump_file) + { + fprintf (symtab->dump_file, + "ODR and non-ODR type conflict: "); + print_generic_expr (symtab->dump_file, t); + fprintf (symtab->dump_file, " and "); + print_generic_expr (symtab->dump_file, nonodr); + fprintf (symtab->dump_file, " mangled:%s\n", + IDENTIFIER_POINTER + (DECL_ASSEMBLER_NAME (TYPE_NAME (t)))); + } + /* Set canonical for T and all other ODR equivalent duplicates + including incomplete structures. */ + set_type_canonical_for_odr_type (t, nonodr); + } + else + { + tree prevail = prevailing_odr_type (t); + + if (symtab->dump_file) + { + fprintf (symtab->dump_file, + "New canonical ODR type: "); + print_generic_expr (symtab->dump_file, t); + fprintf (symtab->dump_file, " mangled:%s\n", + IDENTIFIER_POINTER + (DECL_ASSEMBLER_NAME (TYPE_NAME (t)))); + } + /* Set canonical for T and all other ODR equivalent duplicates + including incomplete structures. */ + set_type_canonical_for_odr_type (t, prevail); + enable_odr_based_tbaa (t); + if (!type_in_anonymous_namespace_p (t)) + hash = htab_hash_string (IDENTIFIER_POINTER + (DECL_ASSEMBLER_NAME + (TYPE_NAME (t)))); + else + hash = TYPE_UID (t); + + /* All variants of t now have TYPE_CANONICAL set to prevail. + Update canonical type hash cache accordingly. */ + num_canonical_type_hash_entries++; + bool existed_p = canonical_type_hash_cache->put (prevail, hash); + gcc_checking_assert (!existed_p); + } + return hash; + } + slot = htab_find_slot_with_hash (gimple_canonical_types, t, hash, INSERT); if (*slot) { @@ -413,6 +492,7 @@ gimple_register_canonical_type_1 (tree t, hashval_t hash) bool existed_p = canonical_type_hash_cache->put (t, hash); gcc_assert (!existed_p); } + return hash; } /* Register type T in the global type table gimple_types and set @@ -464,6 +544,34 @@ lto_register_canonical_types (tree node, bool first_p) gimple_register_canonical_type (node); } +/* Finish canonical type calculation: after all units has been streamed in we + can check if given ODR type structurally conflicts with a non-ODR type. In + the first case we set type canonical according to the canonical type hash. + In the second case we use type names. */ + +static void +lto_register_canonical_types_for_odr_types () +{ + tree t; + unsigned int i; + + if (!types_to_register) + return; + + type_streaming_finished = true; + + /* Be sure that no types derived from ODR types was + not inserted into the hash table. */ + if (flag_checking) + FOR_EACH_VEC_ELT (*types_to_register, i, t) + gcc_assert (!TYPE_CANONICAL (t)); + + /* Register all remaining types. */ + FOR_EACH_VEC_ELT (*types_to_register, i, t) + if (!TYPE_CANONICAL (t)) + gimple_register_canonical_type (t); +} + /* Remember trees that contains references to declarations. */ vec *tree_with_vars; @@ -1657,6 +1765,7 @@ unify_scc (struct data_in *data_in, unsigned from, } + /* Read all the symbols from buffer DATA, using descriptors in DECL_DATA. RESOLUTIONS is the set of symbols picked by the linker (read from the resolution file when the linker plugin is being used). */ @@ -1749,12 +1858,23 @@ lto_read_decls (struct lto_file_decl_data *decl_data, const void *data, num_prevailing_types++; lto_fixup_prevailing_type (t); - /* Compute the canonical type of all types. + /* Compute the canonical type of all non-ODR types. + Delay ODR types for the end of merging process - the canonical + type for those can be computed using the (unique) name however + we want to do this only if units in other languages do not + contain structurally equivalent type. + Because SCC components are streamed in random (hash) order we may have encountered the type before while registering type canonical of a derived type in the same SCC. */ if (!TYPE_CANONICAL (t)) - gimple_register_canonical_type (t); + { + if (!RECORD_OR_UNION_TYPE_P (t) + || !TYPE_CXX_ODR_P (t)) + gimple_register_canonical_type (t); + else if (COMPLETE_TYPE_P (t)) + vec_safe_push (types_to_register, t); + } if (TYPE_MAIN_VARIANT (t) == t && odr_type_p (t)) register_odr_type (t); } @@ -2605,6 +2725,8 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames) ggc_free(decl_data); real_file_decl_data = NULL; + lto_register_canonical_types_for_odr_types (); + if (resolution_file_name) fclose (resolution); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 41918c86677..250efa3e072 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-06-27 Jan Hubicka + + * g++.dg/lto/alias-2_0.C: New testcase. + * g++.dg/lto/alias-2_1.C: New testcase. + 2019-06-27 Jakub Jelinek PR target/90991 diff --git a/gcc/testsuite/g++.dg/lto/alias-2_0.C b/gcc/testsuite/g++.dg/lto/alias-2_0.C new file mode 100644 index 00000000000..ef2d8f9279a --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/alias-2_0.C @@ -0,0 +1,31 @@ +/* { dg-lto-do run } */ +/* { dg-lto-options { { -O2 -flto } } } */ + +/* With LTO we consider all pointers to incomplete types to be possibly + aliasing. This makes *bptr to alias with aptr. + For C++ ODR types we however can work out that they are actually + different. */ + +#include + +typedef int (*fnptr) (); + +__attribute__ ((used)) +struct a *aptr; + +__attribute__ ((used)) +struct b **bptr = (struct b**)&aptr; +extern void init (); +extern void inline_me_late (int); + + +int +main (int argc, char **argv) +{ + init (); + aptr = 0; + inline_me_late (argc); + if (!__builtin_constant_p (aptr == 0)) + __builtin_abort (); + return (size_t)aptr; +} diff --git a/gcc/testsuite/g++.dg/lto/alias-2_1.C b/gcc/testsuite/g++.dg/lto/alias-2_1.C new file mode 100644 index 00000000000..1cbebf1ef0d --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/alias-2_1.C @@ -0,0 +1,16 @@ +#include +struct a {int a;} a; +struct b {int b;} b; +extern struct b **bptr; +void +inline_me_late (int argc) +{ + if (argc == -1) + *bptr = (struct b *)(size_t)1; +} +void +init() +{ + a.a=1; + b.b=2; +} diff --git a/gcc/tree.c b/gcc/tree.c index 2032a936973..34912583bba 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -14101,6 +14101,7 @@ gimple_canonical_types_compatible_p (const_tree t1, const_tree t2, gcc_assert (!trust_type_canonical || (type_with_alias_set_p (t1) && type_with_alias_set_p (t2))); + /* If the types have been previously registered and found equal they still are. */ @@ -14118,6 +14119,14 @@ gimple_canonical_types_compatible_p (const_tree t1, const_tree t2, return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2); } + /* For types where we do ODR based TBAA the canonical type is always + set correctly, so we know that types are different if their + canonical types does not match. */ + if (trust_type_canonical + && (odr_type_p (t1) && odr_based_tbaa_p (t1)) + != (odr_type_p (t2) && odr_based_tbaa_p (t2))) + return false; + /* Can't be the same type if the types don't have the same code. */ enum tree_code code = tree_code_for_canonical_type_merging (TREE_CODE (t1)); if (code != tree_code_for_canonical_type_merging (TREE_CODE (t2)))