class.c (layout_class_type): Set TYPE_CXX_ODR_P for as-base type copy.
authorJan Hubicka <jh@suse.cz>
Thu, 27 Jun 2019 12:07:43 +0000 (14:07 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Thu, 27 Jun 2019 12:07:43 +0000 (12:07 +0000)
* 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

gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/class.c
gcc/ipa-devirt.c
gcc/ipa-utils.h
gcc/lto/lto-common.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/lto/alias-2_0.C [new file with mode: 0644]
gcc/testsuite/g++.dg/lto/alias-2_1.C [new file with mode: 0644]
gcc/tree.c

index f536afb5ee3b8bba494de3ff394bba72d3a80646..948948f20fd5e6f3444c4ac1d38f9f35abdabf7c 100644 (file)
@@ -1,3 +1,14 @@
+2019-06-27  Jan Hubicka  <jh@suse.cz>
+
+       * 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  <mliska@suse.cz>
 
        PR tree-optimization/90974
index 8314b9762f66c040ace4852c266a1917d661d9f8..e616765143193b6de6dcaa1d846d76fa0e774563 100644 (file)
@@ -1,3 +1,8 @@
+2019-06-27  Jan Hubicka  <jh@suse.cz>
+
+       * class.c (layout_class_type): Set TYPE_CXX_ODR_P for as-base
+       type copy.
+
 2019-06-27  Martin Liska  <mliska@suse.cz>
 
        * class.c (adjust_clone_args): Remove obviously
index 18e7db08c8df5541f5872fba6065d6cbd5f771fa..73291b341fe8815d433f46f959bf2640675e4b04 100644 (file)
@@ -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.  */
index a4c8b0de86f7ab62e436f877da78f606c1f5ed4c..252d9206181ebdd61dc7ca80e4d4a0e391b510fd 100644 (file)
@@ -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 <tree> (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
index 64974beb6d4040fd492b313afca65682cd092536..22e6970234a448d52ddcff4ef53037a1e65b7957 100644 (file)
@@ -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. 
index 0d38ee6b57b31f367a0cd29ff80bdba0c4f4048c..1275b673506a414add8fe24d532947a863f7ecaa 100644 (file)
@@ -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<const_tree, hashval_t> *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<tree, va_gc> *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, va_gc> *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);
 
index 41918c8667795ca07c1dccc7835c424327e64b32..250efa3e072a4675c6c863591e39517f443717c5 100644 (file)
@@ -1,3 +1,8 @@
+2019-06-27  Jan Hubicka  <jh@suse.cz>
+
+       * g++.dg/lto/alias-2_0.C: New testcase.
+       * g++.dg/lto/alias-2_1.C: New testcase.
+
 2019-06-27  Jakub Jelinek  <jakub@redhat.com>
 
        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 (file)
index 0000000..ef2d8f9
--- /dev/null
@@ -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 <string.h>
+
+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 (file)
index 0000000..1cbebf1
--- /dev/null
@@ -0,0 +1,16 @@
+#include <string.h>
+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;
+}
index 2032a936973ddbc96c041f4c72897d006d250d69..34912583bba4ebee064a9fb4349465d05abde6c2 100644 (file)
@@ -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)))