Update gcc-50 to SVN version 221423
authorJohn Marino <draco@marino.st>
Fri, 13 Mar 2015 13:20:38 +0000 (14:20 +0100)
committerJohn Marino <draco@marino.st>
Fri, 13 Mar 2015 15:03:39 +0000 (16:03 +0100)
Last Changed Date: 2015-03-13 14:48:21 +0100 (Fri, 13 Mar 2015)

65 files changed:
contrib/gcc-5.0/LAST_UPDATED
contrib/gcc-5.0/gcc/DATESTAMP
contrib/gcc-5.0/gcc/asan.c
contrib/gcc-5.0/gcc/c-family/c-common.c
contrib/gcc-5.0/gcc/c-family/c.opt
contrib/gcc-5.0/gcc/c/c-convert.c
contrib/gcc-5.0/gcc/c/c-decl.c
contrib/gcc-5.0/gcc/c/c-parser.c
contrib/gcc-5.0/gcc/c/c-typeck.c
contrib/gcc-5.0/gcc/cfgexpand.c
contrib/gcc-5.0/gcc/cgraph.c
contrib/gcc-5.0/gcc/cgraph.h
contrib/gcc-5.0/gcc/config/i386/i386.c
contrib/gcc-5.0/gcc/config/i386/i386.md
contrib/gcc-5.0/gcc/config/i386/intelmic-mkoffload.c
contrib/gcc-5.0/gcc/config/i386/linux-common.h
contrib/gcc-5.0/gcc/cp/call.c
contrib/gcc-5.0/gcc/cp/cp-gimplify.c
contrib/gcc-5.0/gcc/cp/decl.c
contrib/gcc-5.0/gcc/cp/parser.c
contrib/gcc-5.0/gcc/cp/pt.c
contrib/gcc-5.0/gcc/doc/extend.texi
contrib/gcc-5.0/gcc/doc/invoke.texi
contrib/gcc-5.0/gcc/dominance.c
contrib/gcc-5.0/gcc/fold-const.c
contrib/gcc-5.0/gcc/gcc.c
contrib/gcc-5.0/gcc/graph.c
contrib/gcc-5.0/gcc/ipa-chkp.c
contrib/gcc-5.0/gcc/ipa-devirt.c
contrib/gcc-5.0/gcc/ipa-icf-gimple.c
contrib/gcc-5.0/gcc/ipa-icf-gimple.h
contrib/gcc-5.0/gcc/ipa-icf.c
contrib/gcc-5.0/gcc/ipa-icf.h
contrib/gcc-5.0/gcc/ipa-inline-analysis.c
contrib/gcc-5.0/gcc/ipa-utils.h
contrib/gcc-5.0/gcc/lra-lives.c
contrib/gcc-5.0/gcc/lto/lto.c
contrib/gcc-5.0/gcc/omp-low.c
contrib/gcc-5.0/gcc/simplify-rtx.c
contrib/gcc-5.0/gcc/symtab.c
contrib/gcc-5.0/gcc/toplev.c
contrib/gcc-5.0/gcc/tree-cfg.c
contrib/gcc-5.0/gcc/tree-cfgcleanup.c
contrib/gcc-5.0/gcc/tree-core.h
contrib/gcc-5.0/gcc/tree-inline.c
contrib/gcc-5.0/gcc/tree-parloops.c
contrib/gcc-5.0/gcc/tree-sra.c
contrib/gcc-5.0/gcc/tree-ssa-coalesce.c
contrib/gcc-5.0/gcc/tree-ssa-coalesce.h
contrib/gcc-5.0/gcc/tree-ssa-dom.c
contrib/gcc-5.0/gcc/tree-ssa-forwprop.c
contrib/gcc-5.0/gcc/tree-ssa-pre.c
contrib/gcc-5.0/gcc/tree-ssa-propagate.c
contrib/gcc-5.0/gcc/tree-ssa-tail-merge.c
contrib/gcc-5.0/gcc/tree-vect-data-refs.c
contrib/gcc-5.0/gcc/tree-vect-stmts.c
contrib/gcc-5.0/gcc/tree-vectorizer.c
contrib/gcc-5.0/gcc/tree.h
contrib/gcc-5.0/gcc/ubsan.c
contrib/gcc-5.0/gcc/var-tracking.c
contrib/gcc-5.0/gcc/varasm.c
contrib/gcc-5.0/gcc/varpool.c
contrib/gcc-5.0/libstdc++-v3/include/bits/regex.h
contrib/gcc-5.0/libstdc++-v3/include/bits/regex.tcc
contrib/gcc-5.0/libstdc++-v3/include/experimental/system_error

index 3a6f495..d8c9337 100644 (file)
@@ -1,2 +1,2 @@
-221261
-Last Changed Date: 2015-03-08 01:16:18 +0100 (Sun, 08 Mar 2015)
+221423
+Last Changed Date: 2015-03-13 14:48:21 +0100 (Fri, 13 Mar 2015)
index b7c2b11..9e4a629 100644 (file)
@@ -1820,6 +1820,8 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
     {
       if (DECL_THREAD_LOCAL_P (inner))
        return;
+      if (!ASAN_GLOBALS && is_global_var (inner))
+        return;
       if (!TREE_STATIC (inner))
        {
          /* Automatic vars in the current function will be always
index 8c23e09..456c619 100644 (file)
@@ -1800,6 +1800,12 @@ warn_logical_not_parentheses (location_t location, enum tree_code code,
       || TREE_CODE (TREE_TYPE (rhs)) == BOOLEAN_TYPE)
     return;
 
+  /* Don't warn for !x == 0 or !y != 0, those are equivalent to
+     !(x == 0) or !(y != 0).  */
+  if ((code == EQ_EXPR || code == NE_EXPR)
+      && integer_zerop (rhs))
+    return;
+
   warning_at (location, OPT_Wlogical_not_parentheses,
              "logical not is only applied to the left hand side of "
              "comparison");
@@ -5452,11 +5458,10 @@ c_common_nodes_and_builtins (void)
       char name[25];
 
       sprintf (name, "__int%d", int_n_data[i].bitsize);
-      record_builtin_type ((enum rid)(RID_FIRST_INT_N + i), xstrdup (name),
+      record_builtin_type ((enum rid)(RID_FIRST_INT_N + i), name,
                           int_n_trees[i].signed_type);
       sprintf (name, "__int%d unsigned", int_n_data[i].bitsize);
-      record_builtin_type (RID_MAX, xstrdup (name),
-                          int_n_trees[i].unsigned_type);
+      record_builtin_type (RID_MAX, name, int_n_trees[i].unsigned_type);
     }
 
   if (c_dialect_cxx ())
index b3c8cee..2692fb5 100644 (file)
@@ -1041,6 +1041,16 @@ fchkp-instrument-marked-only
 C ObjC C++ ObjC++ LTO Report Var(flag_chkp_instrument_marked_only) Init(0)
 Instrument only functions marked with bnd_instrument attribute.
 
+fchkp-use-wrappers
+C ObjC C++ ObjC++ LTO Report Var(flag_chkp_use_wrappers) Init(1)
+Transform instrumented builtin calls into calls to wrappers.
+
+static-libmpx
+Driver
+
+static-libmpxwrappers
+Driver
+
 fcilkplus
 C ObjC C++ ObjC++ LTO Report Var(flag_cilkplus) Init(0)
 Enable Cilk Plus
index 2cb53f7..27fc3fc 100644 (file)
@@ -121,9 +121,7 @@ convert (tree type, tree expr)
       if (flag_sanitize & SANITIZE_FLOAT_CAST
          && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
          && COMPLETE_TYPE_P (type)
-         && current_function_decl != NULL_TREE
-         && !lookup_attribute ("no_sanitize_undefined",
-                               DECL_ATTRIBUTES (current_function_decl)))
+         && do_ubsan_in_current_function ())
        {
          tree arg;
          if (in_late_binary_op)
index 7497858..c140837 100644 (file)
@@ -5837,10 +5837,7 @@ grokdeclarator (const struct c_declarator *declarator,
                    warn_variable_length_array (name, size);
                    if (flag_sanitize & SANITIZE_VLA
                        && decl_context == NORMAL
-                       && current_function_decl != NULL_TREE
-                       && !lookup_attribute ("no_sanitize_undefined",
-                                             DECL_ATTRIBUTES
-                                               (current_function_decl)))
+                       && do_ubsan_in_current_function ())
                      {
                        /* Evaluate the array size only once.  */
                        size = c_save_expr (size);
index ceb9e1a..5cc3892 100644 (file)
@@ -139,7 +139,7 @@ c_parse_init (void)
       /* We always create the symbols but they aren't always supported.  */
       char name[50];
       sprintf (name, "__int%d", int_n_data[i].bitsize);
-      id = get_identifier (xstrdup (name));
+      id = get_identifier (name);
       C_SET_RID_CODE (id, RID_FIRST_INT_N + i);
       C_IS_RESERVED_WORD (id) = 1;
     }
index a3a9c77..ebe4c73 100644 (file)
@@ -3459,9 +3459,36 @@ parser_build_binary_op (location_t location, enum tree_code code,
                           code1, arg1.value, code2, arg2.value);
 
   if (warn_logical_not_paren
+      && TREE_CODE_CLASS (code) == tcc_comparison
       && code1 == TRUTH_NOT_EXPR
-      && code2 != TRUTH_NOT_EXPR)
-    warn_logical_not_parentheses (location, code, arg2.value);
+      && code2 != TRUTH_NOT_EXPR
+      /* Avoid warning for !!x == y.  */
+      && (TREE_CODE (arg1.value) != NE_EXPR
+         || !integer_zerop (TREE_OPERAND (arg1.value, 1))))
+    {
+      /* Avoid warning for !b == y where b has _Bool type.  */
+      tree t = integer_zero_node;
+      if (TREE_CODE (arg1.value) == EQ_EXPR
+         && integer_zerop (TREE_OPERAND (arg1.value, 1))
+         && TREE_TYPE (TREE_OPERAND (arg1.value, 0)) == integer_type_node)
+       {
+         t = TREE_OPERAND (arg1.value, 0);
+         do
+           {
+             if (TREE_TYPE (t) != integer_type_node)
+               break;
+             if (TREE_CODE (t) == C_MAYBE_CONST_EXPR)
+               t = C_MAYBE_CONST_EXPR_EXPR (t);
+             else if (CONVERT_EXPR_P (t))
+               t = TREE_OPERAND (t, 0);
+             else
+               break;
+           }
+         while (1);
+       }
+      if (TREE_CODE (TREE_TYPE (t)) != BOOLEAN_TYPE)
+       warn_logical_not_parentheses (location, code, arg2.value);
+    }
 
   /* Warn about comparisons against string literals, with the exception
      of testing for equality or inequality of a string literal with NULL.  */
@@ -11229,9 +11256,7 @@ build_binary_op (location_t location, enum tree_code code,
 
   if ((flag_sanitize & (SANITIZE_SHIFT | SANITIZE_DIVIDE
                        | SANITIZE_FLOAT_DIVIDE))
-      && current_function_decl != 0
-      && !lookup_attribute ("no_sanitize_undefined",
-                           DECL_ATTRIBUTES (current_function_decl))
+      && do_ubsan_in_current_function ()
       && (doing_div_or_mod || doing_shift))
     {
       /* OP0 and/or OP1 might have side-effects.  */
index 569cd0d..67be09f 100644 (file)
@@ -3921,6 +3921,31 @@ expand_debug_expr (tree exp)
       op1 = expand_debug_expr (TREE_OPERAND (exp, 1));
       if (!op1)
        return NULL_RTX;
+      switch (TREE_CODE (exp))
+       {
+       case LSHIFT_EXPR:
+       case RSHIFT_EXPR:
+       case LROTATE_EXPR:
+       case RROTATE_EXPR:
+       case WIDEN_LSHIFT_EXPR:
+         /* Ensure second operand isn't wider than the first one.  */
+         inner_mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 1)));
+         if (SCALAR_INT_MODE_P (inner_mode))
+           {
+             machine_mode opmode = mode;
+             if (VECTOR_MODE_P (mode))
+               opmode = GET_MODE_INNER (mode);
+             if (SCALAR_INT_MODE_P (opmode)
+                 && (GET_MODE_PRECISION (opmode)
+                     < GET_MODE_PRECISION (inner_mode)))
+               op1 = simplify_gen_subreg (opmode, op1, inner_mode,
+                                          subreg_lowpart_offset (opmode,
+                                                                 inner_mode));
+           }
+         break;
+       default:
+         break;
+       }
       /* Fall through.  */
 
     unary:
@@ -5124,13 +5149,11 @@ reorder_operands (basic_block bb)
        continue;
       /* Swap operands if the second one is more expensive.  */
       def0 = get_gimple_for_ssa_name (op0);
-      if (!def0)
-       continue;
       def1 = get_gimple_for_ssa_name (op1);
       if (!def1)
        continue;
       swap = false;
-      if (lattice[gimple_uid (def1)] > lattice[gimple_uid (def0)])
+      if (!def0 || lattice[gimple_uid (def1)] > lattice[gimple_uid (def0)])
        swap = true;
       if (swap)
        {
@@ -5139,7 +5162,7 @@ reorder_operands (basic_block bb)
              fprintf (dump_file, "Swap operands in stmt:\n");
              print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
              fprintf (dump_file, "Cost left opnd=%d, right opnd=%d\n",
-                      lattice[gimple_uid (def0)],
+                      def0 ? lattice[gimple_uid (def0)] : 0,
                       lattice[gimple_uid (def1)]);
            }
          swap_ssa_operands (stmt, gimple_assign_rhs1_ptr (stmt),
index b2109bd..ede58bf 100644 (file)
@@ -663,7 +663,19 @@ cgraph_node::get_for_asmname (tree asmname)
 hashval_t
 cgraph_edge_hasher::hash (cgraph_edge *e)
 {
-  return htab_hash_pointer (e->call_stmt);
+  /* This is a really poor hash function, but it is what htab_hash_pointer
+     uses.  */
+  return (hashval_t) ((intptr_t)e->call_stmt >> 3);
+}
+
+/* Returns a hash value for X (which really is a cgraph_edge).  */
+
+hashval_t
+cgraph_edge_hasher::hash (gimple call_stmt)
+{
+  /* This is a really poor hash function, but it is what htab_hash_pointer
+     uses.  */
+  return (hashval_t) ((intptr_t)call_stmt >> 3);
 }
 
 /* Return nonzero if the call_stmt of of cgraph_edge X is stmt *Y.  */
@@ -680,9 +692,8 @@ static inline void
 cgraph_update_edge_in_call_site_hash (cgraph_edge *e)
 {
   gimple call = e->call_stmt;
-  *e->caller->call_site_hash->find_slot_with_hash (call,
-                                                  htab_hash_pointer (call),
-                                                  INSERT) = e;
+  *e->caller->call_site_hash->find_slot_with_hash
+      (call, cgraph_edge_hasher::hash (call), INSERT) = e;
 }
 
 /* Add call graph edge E to call site hash of its caller.  */
@@ -695,8 +706,7 @@ cgraph_add_edge_to_call_site_hash (cgraph_edge *e)
   if (e->speculative && e->indirect_unknown_callee)
     return;
   cgraph_edge **slot = e->caller->call_site_hash->find_slot_with_hash
-                                  (e->call_stmt,
-                                   htab_hash_pointer (e->call_stmt), INSERT);
+      (e->call_stmt, cgraph_edge_hasher::hash (e->call_stmt), INSERT);
   if (*slot)
     {
       gcc_assert (((cgraph_edge *)*slot)->speculative);
@@ -718,8 +728,8 @@ cgraph_node::get_edge (gimple call_stmt)
   int n = 0;
 
   if (call_site_hash)
-    return call_site_hash->find_with_hash (call_stmt,
-                                          htab_hash_pointer (call_stmt));
+    return call_site_hash->find_with_hash
+       (call_stmt, cgraph_edge_hasher::hash (call_stmt));
 
   /* This loop may turn out to be performance problem.  In such case adding
      hashtables into call nodes with very many edges is probably best
@@ -782,7 +792,7 @@ cgraph_edge::set_call_stmt (gcall *new_stmt, bool update_speculative)
       && (!speculative || !indirect_unknown_callee))
     {
       caller->call_site_hash->remove_elt_with_hash
-       (call_stmt, htab_hash_pointer (call_stmt));
+       (call_stmt, cgraph_edge_hasher::hash (call_stmt));
     }
 
   cgraph_edge *e = this;
@@ -987,8 +997,8 @@ cgraph_edge::remove_caller (void)
        caller->callees = next_callee;
     }
   if (caller->call_site_hash)
-    caller->call_site_hash->remove_elt_with_hash (call_stmt,
-                                                 htab_hash_pointer (call_stmt));
+    caller->call_site_hash->remove_elt_with_hash
+       (call_stmt, cgraph_edge_hasher::hash (call_stmt));
 }
 
 /* Put the edge onto the free list.  */
@@ -1711,7 +1721,10 @@ cgraph_node::release_body (bool keep_arguments)
     DECL_INITIAL (decl) = error_mark_node;
   release_function_body (decl);
   if (lto_file_data)
-    lto_free_function_in_decl_state_for_node (this);
+    {
+      lto_free_function_in_decl_state_for_node (this);
+      lto_file_data = NULL;
+    }
 }
 
 /* Remove function from symbol table.  */
@@ -1789,13 +1802,18 @@ cgraph_node::remove (void)
       n = cgraph_node::get (decl);
       if (!n
          || (!n->clones && !n->clone_of && !n->global.inlined_to
-             && (symtab->global_info_ready
+             && ((symtab->global_info_ready || in_lto_p)
                  && (TREE_ASM_WRITTEN (n->decl)
                      || DECL_EXTERNAL (n->decl)
                      || !n->analyzed
                      || (!flag_wpa && n->in_other_partition)))))
        release_body ();
     }
+  else
+    {
+      lto_free_function_in_decl_state_for_node (this);
+      lto_file_data = NULL;
+    }
 
   decl = NULL;
   if (call_site_hash)
@@ -2415,7 +2433,7 @@ nonremovable_p (cgraph_node *node, void *)
    calls to THIS.  */
 
 bool
-cgraph_node::can_remove_if_no_direct_calls_p (void)
+cgraph_node::can_remove_if_no_direct_calls_p (bool will_inline)
 {
   struct ipa_ref *ref;
 
@@ -2430,6 +2448,9 @@ cgraph_node::can_remove_if_no_direct_calls_p (void)
       return !call_for_symbol_and_aliases (nonremovable_p, NULL, true);
     }
 
+  if (will_inline && address_taken)
+    return false;
+
   /* Otheriwse check if we can remove the symbol itself and then verify
      that only uses of the comdat groups are direct call to THIS
      or its aliases.   */
@@ -2454,12 +2475,16 @@ cgraph_node::can_remove_if_no_direct_calls_p (void)
       /* If we see different symbol than THIS, be sure to check calls.  */
       if (next->ultimate_alias_target () != target)
        for (cgraph_edge *e = next->callers; e; e = e->next_caller)
-         if (e->caller->get_comdat_group () != get_comdat_group ())
+         if (e->caller->get_comdat_group () != get_comdat_group ()
+             || will_inline)
            return false;
 
-      for (int i = 0; next->iterate_referring (i, ref); i++)
-       if (ref->referring->get_comdat_group () != get_comdat_group ())
-         return false;
+      /* If function is not being inlined, we care only about
+        references outside of the comdat group.  */
+      if (!will_inline)
+        for (int i = 0; next->iterate_referring (i, ref); i++)
+         if (ref->referring->get_comdat_group () != get_comdat_group ())
+           return false;
     }
   return true;
 }
@@ -2479,9 +2504,9 @@ cgraph_node::can_remove_if_no_direct_calls_p (void)
    linkonce section.  */
 
 bool
-cgraph_node::will_be_removed_from_program_if_no_direct_calls_p (void)
+cgraph_node::will_be_removed_from_program_if_no_direct_calls_p
+        (bool will_inline)
 {
-  struct ipa_ref *ref;
   gcc_assert (!global.inlined_to);
   if (DECL_EXTERNAL (decl))
     return true;
@@ -2496,6 +2521,9 @@ cgraph_node::will_be_removed_from_program_if_no_direct_calls_p (void)
       if (same_comdat_group && externally_visible)
        {
          struct cgraph_node *target = ultimate_alias_target ();
+
+         if (will_inline && address_taken)
+           return true;
          for (cgraph_node *next = dyn_cast<cgraph_node *> (same_comdat_group);
               next != this;
               next = dyn_cast<cgraph_node *> (next->same_comdat_group))
@@ -2510,18 +2538,15 @@ cgraph_node::will_be_removed_from_program_if_no_direct_calls_p (void)
                 be sure to check calls.  */
              if (next->ultimate_alias_target () != target)
                for (cgraph_edge *e = next->callers; e; e = e->next_caller)
-                 if (e->caller->get_comdat_group () != get_comdat_group ())
+                 if (e->caller->get_comdat_group () != get_comdat_group ()
+                     || will_inline)
                    return false;
-
-             for (int i = 0; next->iterate_referring (i, ref); i++)
-               if (ref->referring->get_comdat_group () != get_comdat_group ())
-                 return false;
            }
        }
       return true;
     }
   else
-    return can_remove_if_no_direct_calls_p ();
+    return can_remove_if_no_direct_calls_p (will_inline);
 }
 
 
@@ -3201,6 +3226,8 @@ cgraph_node::get_untransformed_body (void)
   lto_free_section_data (file_data, LTO_section_function_body, name,
                         data, len);
   lto_free_function_in_decl_state_for_node (this);
+  /* Keep lto file data so ipa-inline-analysis knows about cross module
+     inlining.  */
 
   timevar_pop (TV_IPA_LTO_GIMPLE_IN);
 
index c4f39ba..99af026 100644 (file)
@@ -289,6 +289,18 @@ public:
   /* Make DECL local.  */
   void make_decl_local (void);
 
+  /* Return desired alignment of the definition.  This is NOT alignment useful
+     to access THIS, because THIS may be interposable and DECL_ALIGN should
+     be used instead.  It however must be guaranteed when output definition
+     of THIS.  */
+  unsigned int definition_alignment ();
+
+  /* Return true if alignment can be increased.  */
+  bool can_increase_alignment_p ();
+
+  /* Increase alignment of symbol to ALIGN.  */
+  void increase_alignment (unsigned int align);
+
   /* Return true if list contains an alias.  */
   bool has_aliases_p (void);
 
@@ -776,6 +788,7 @@ struct cgraph_edge_hasher : ggc_hasher<cgraph_edge *>
   typedef gimple compare_type;
 
   static hashval_t hash (cgraph_edge *);
+  static hashval_t hash (gimple);
   static bool equal (cgraph_edge *, gimple);
 };
 
@@ -1098,16 +1111,23 @@ public:
      all uses of COMDAT function does not make it necessarily disappear from
      the program unless we are compiling whole program or we do LTO.  In this
      case we know we win since dynamic linking will not really discard the
-     linkonce section.  */
-  bool will_be_removed_from_program_if_no_direct_calls_p (void);
+     linkonce section.  
+
+     If WILL_INLINE is true, assume that function will be inlined into all the
+     direct calls.  */
+  bool will_be_removed_from_program_if_no_direct_calls_p
+        (bool will_inline = false);
 
   /* Return true when function can be removed from callgraph
-     if all direct calls are eliminated.  */
+     if all direct calls and references are eliminated.  The function does
+     not take into account comdat groups.  */
   bool can_remove_if_no_direct_calls_and_refs_p (void);
 
   /* Return true when function cgraph_node and its aliases can be removed from
-     callgraph if all direct calls are eliminated.  */
-  bool can_remove_if_no_direct_calls_p (void);
+     callgraph if all direct calls are eliminated. 
+     If WILL_INLINE is true, assume that function will be inlined into all the
+     direct calls.  */
+  bool can_remove_if_no_direct_calls_p (bool will_inline = false);
 
   /* Return true when callgraph node is a function with Gimple body defined
      in current unit.  Functions can also be define externally or they
index ab8f03a..47deda7 100644 (file)
@@ -12931,30 +12931,26 @@ ix86_address_cost (rtx x, machine_mode, addr_space_t, bool)
   if (parts.index && GET_CODE (parts.index) == SUBREG)
     parts.index = SUBREG_REG (parts.index);
 
-  /* Attempt to minimize number of registers in the address.  */
-  if ((parts.base
-       && (!REG_P (parts.base) || REGNO (parts.base) >= FIRST_PSEUDO_REGISTER))
-      || (parts.index
-         && (!REG_P (parts.index)
-             || REGNO (parts.index) >= FIRST_PSEUDO_REGISTER)))
-    cost++;
-
-  /* When address base or index is "pic_offset_table_rtx" we don't increase
-     address cost.  When a memopt with "pic_offset_table_rtx" is not invariant
-     itself it most likely means that base or index is not invariant.
-     Therefore only "pic_offset_table_rtx" could be hoisted out, which is not
-     profitable for x86.  */
+  /* Attempt to minimize number of registers in the address by increasing
+     address cost for each used register.  We don't increase address cost
+     for "pic_offset_table_rtx".  When a memopt with "pic_offset_table_rtx"
+     is not invariant itself it most likely means that base or index is not
+     invariant.  Therefore only "pic_offset_table_rtx" could be hoisted out,
+     which is not profitable for x86.  */
   if (parts.base
-      && (current_pass->type == GIMPLE_PASS
-         || (!pic_offset_table_rtx
-             || REGNO (pic_offset_table_rtx) != REGNO(parts.base)))
       && (!REG_P (parts.base) || REGNO (parts.base) >= FIRST_PSEUDO_REGISTER)
-      && parts.index
       && (current_pass->type == GIMPLE_PASS
-         || (!pic_offset_table_rtx
-             || REGNO (pic_offset_table_rtx) != REGNO(parts.index)))
+         || !pic_offset_table_rtx
+         || !REG_P (parts.base)
+         || REGNO (pic_offset_table_rtx) != REGNO (parts.base)))
+    cost++;
+
+  if (parts.index
       && (!REG_P (parts.index) || REGNO (parts.index) >= FIRST_PSEUDO_REGISTER)
-      && parts.base != parts.index)
+      && (current_pass->type == GIMPLE_PASS
+         || !pic_offset_table_rtx
+         || !REG_P (parts.index)
+         || REGNO (pic_offset_table_rtx) != REGNO (parts.index)))
     cost++;
 
   /* AMD-K6 don't like addresses with ModR/M set to 00_xxx_100b,
index 8a80415..1129b93 100644 (file)
    (set_attr "mode" "<MODE>")])
 
 ;; BMI2 instructions.
-(define_insn "bmi2_bzhi_<mode>3"
+(define_expand "bmi2_bzhi_<mode>3"
+  [(parallel
+    [(set (match_operand:SWI48 0 "register_operand")
+         (zero_extract:SWI48
+           (match_operand:SWI48 1 "nonimmediate_operand")
+           (umin:SWI48
+             (and:SWI48 (match_operand:SWI48 2 "register_operand")
+                        (const_int 255))
+             (match_dup 3))
+           (const_int 0)))
+     (clobber (reg:CC FLAGS_REG))])]
+  "TARGET_BMI2"
+  "operands[3] = GEN_INT (<MODE_SIZE> * BITS_PER_UNIT);")
+
+(define_insn "*bmi2_bzhi_<mode>3"
   [(set (match_operand:SWI48 0 "register_operand" "=r")
-       (and:SWI48 (lshiftrt:SWI48 (const_int -1)
-                                  (match_operand:SWI48 2 "register_operand" "r"))
-                  (match_operand:SWI48 1 "nonimmediate_operand" "rm")))
+       (zero_extract:SWI48
+         (match_operand:SWI48 1 "nonimmediate_operand" "rm")
+         (umin:SWI48
+           (and:SWI48 (match_operand:SWI48 2 "register_operand" "r")
+                      (const_int 255))
+           (match_operand:SWI48 3 "const_int_operand" "n"))
+         (const_int 0)))
    (clobber (reg:CC FLAGS_REG))]
-  "TARGET_BMI2"
+  "TARGET_BMI2 && INTVAL (operands[3]) == <MODE_SIZE> * BITS_PER_UNIT"
   "bzhi\t{%2, %1, %0|%0, %1, %2}"
   [(set_attr "type" "bitmanip")
    (set_attr "prefix" "vex")
    (set_attr "mode" "<MODE>")])
 
+(define_mode_attr k [(SI "k") (DI "q")])
+(define_insn "*bmi2_bzhi_<mode>3_1"
+  [(set (match_operand:SWI48 0 "register_operand" "=r")
+       (zero_extract:SWI48
+         (match_operand:SWI48 1 "nonimmediate_operand" "rm")
+         (umin:SWI48
+           (zero_extend:SWI48 (match_operand:QI 2 "register_operand" "r"))
+           (match_operand:SWI48 3 "const_int_operand" "n"))
+         (const_int 0)))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_BMI2 && INTVAL (operands[3]) == <MODE_SIZE> * BITS_PER_UNIT"
+  "bzhi\t{%<k>2, %1, %0|%0, %1, %<k>2}"
+  [(set_attr "type" "bitmanip")
+   (set_attr "prefix" "vex")
+   (set_attr "mode" "<MODE>")])
+
 (define_insn "bmi2_pdep_<mode>3"
   [(set (match_operand:SWI48 0 "register_operand" "=r")
         (unspec:SWI48 [(match_operand:SWI48 1 "register_operand" "r")
index e6394e9..f93007c 100644 (file)
 
 #include "config.h"
 #include <libgen.h>
-#include "libgomp-plugin.h"
 #include "system.h"
 #include "coretypes.h"
 #include "obstack.h"
 #include "intl.h"
 #include "diagnostic.h"
 #include "collect-utils.h"
+#include "intelmic-offload.h"
 
 const char tool_name[] = "intelmic mkoffload";
 
@@ -158,10 +158,21 @@ find_target_compiler (const char *name)
   bool found = false;
   char **paths = NULL;
   unsigned n_paths, i;
-  const char *collect_path = dirname (ASTRDUP (getenv ("COLLECT_GCC")));
-  size_t len = strlen (collect_path) + 1 + strlen (name) + 1;
-  char *target_compiler = XNEWVEC (char, len);
-  sprintf (target_compiler, "%s/%s", collect_path, name);
+  char *target_compiler;
+  const char *collect_gcc = getenv ("COLLECT_GCC");
+  const char *gcc_path = dirname (ASTRDUP (collect_gcc));
+  const char *gcc_exec = basename (ASTRDUP (collect_gcc));
+
+  if (strcmp (gcc_exec, collect_gcc) == 0)
+    {
+      /* collect_gcc has no path, so it was found in PATH.  Make sure we also
+        find accel-gcc in PATH.  */
+      target_compiler = XDUPVEC (char, name, strlen (name) + 1);
+      found = true;
+      goto out;
+    }
+
+  target_compiler = concat (gcc_path, "/", name, NULL);
   if (access_check (target_compiler, X_OK) == 0)
     {
       found = true;
@@ -171,7 +182,7 @@ find_target_compiler (const char *name)
   n_paths = parse_env_var (getenv ("COMPILER_PATH"), &paths);
   for (i = 0; i < n_paths; i++)
     {
-      len = strlen (paths[i]) + 1 + strlen (name) + 1;
+      size_t len = strlen (paths[i]) + 1 + strlen (name) + 1;
       target_compiler = XRESIZEVEC (char, target_compiler, len);
       sprintf (target_compiler, "%s/%s", paths[i], name);
       if (access_check (target_compiler, X_OK) == 0)
@@ -346,7 +357,7 @@ generate_host_descr_file (const char *host_compiler)
           "init (void)\n"
           "{\n"
           "  GOMP_offload_register (&__OFFLOAD_TABLE__, %d, __offload_target_data);\n"
-          "}\n", OFFLOAD_TARGET_TYPE_INTEL_MIC);
+          "}\n", GOMP_DEVICE_INTEL_MIC);
   fclose (src_file);
 
   unsigned new_argc = 0;
@@ -483,8 +494,7 @@ main (int argc, char **argv)
   if (!host_compiler)
     fatal_error (input_location, "COLLECT_GCC must be set");
 
-  const char *target_driver_name
-    = DEFAULT_REAL_TARGET_MACHINE "-accel-" DEFAULT_TARGET_MACHINE "-gcc";
+  const char *target_driver_name = GCC_INSTALL_NAME;
   char *target_compiler = find_target_compiler (target_driver_name);
   if (target_compiler == NULL)
     fatal_error (input_location, "offload compiler %s not found",
index f93d71d..9c6560b 100644 (file)
@@ -53,3 +53,41 @@ along with GCC; see the file COPYING3.  If not see
                       GNU_USER_TARGET_ENDFILE_SPEC,     \
                       GNU_USER_TARGET_MATHFILE_SPEC " " \
                       ANDROID_ENDFILE_SPEC)
+
+#ifndef LIBMPX_LIBS
+#define LIBMPX_LIBS "\
+ %:include(libmpx.spec)%(link_libmpx)"
+#endif
+
+#ifndef LIBMPX_SPEC
+#if defined(HAVE_LD_STATIC_DYNAMIC)
+#define LIBMPX_SPEC "\
+%{mmpx:%{fcheck-pointer-bounds:\
+    %{static:--whole-archive -lmpx --no-whole-archive" LIBMPX_LIBS "}\
+    %{!static:%{static-libmpx:" LD_STATIC_OPTION " --whole-archive}\
+    -lmpx %{static-libmpx:--no-whole-archive " LD_DYNAMIC_OPTION \
+    LIBMPX_LIBS "}}}}"
+#else
+#define LIBMPX_SPEC "\
+%{mmpx:%{fcheck-pointer-bounds:-lmpx" LIBMPX_LIBS "}}"
+#endif
+#endif
+
+#ifndef LIBMPXWRAPPERS_SPEC
+#if defined(HAVE_LD_STATIC_DYNAMIC)
+#define LIBMPXWRAPPERS_SPEC "\
+%{mmpx:%{fcheck-pointer-bounds:%{!fno-chkp-use-wrappers:\
+    %{static:-lmpxwrappers}\
+    %{!static:%{static-libmpxwrappers:" LD_STATIC_OPTION " --whole-archive}\
+    -lmpxwrappers %{static-libmpxwrappers:--no-whole-archive "\
+    LD_DYNAMIC_OPTION "}}}}}"
+#else
+#define LIBMPXWRAPPERS_SPEC "\
+%{mmpx:%{fcheck-pointer-bounds:{!fno-chkp-use-wrappers:-lmpxwrappers}}}"
+#endif
+#endif
+
+#ifndef CHKP_SPEC
+#define CHKP_SPEC "\
+%{!nostdlib:%{!nodefaultlibs:" LIBMPX_SPEC LIBMPXWRAPPERS_SPEC "}}"
+#endif
index 2b15185..fdd8436 100644 (file)
@@ -8020,7 +8020,11 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
      that would be captured if the call turns out to be to a
      non-static member function.  Do not actually capture it at this
      point.  */
-  first_mem_arg = maybe_resolve_dummy (instance, false);
+  if (DECL_CONSTRUCTOR_P (fn))
+    /* Constructors don't use the enclosing 'this'.  */
+    first_mem_arg = instance;
+  else
+    first_mem_arg = maybe_resolve_dummy (instance, false);
 
   /* Get the high-water mark for the CONVERSION_OBSTACK.  */
   p = conversion_obstack_alloc (0);
index 4233a64..70645b5 100644 (file)
@@ -53,6 +53,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "c-family/c-ubsan.h"
 #include "cilk.h"
+#include "gimplify.h"
+#include "gimple-expr.h"
 
 /* Forward declarations.  */
 
@@ -528,6 +530,29 @@ gimplify_must_not_throw_expr (tree *expr_p, gimple_seq *pre_p)
   return GS_ALL_DONE;
 }
 
+/* Return TRUE if an operand (OP) of a given TYPE being copied is
+   really just an empty class copy.
+
+   Check that the operand has a simple form so that TARGET_EXPRs and
+   non-empty CONSTRUCTORs get reduced properly, and we leave the
+   return slot optimization alone because it isn't a copy.  */
+
+static bool
+simple_empty_class_p (tree type, tree op)
+{
+  return
+    ((TREE_CODE (op) == COMPOUND_EXPR
+      && simple_empty_class_p (type, TREE_OPERAND (op, 1)))
+     || is_gimple_lvalue (op)
+     || INDIRECT_REF_P (op)
+     || (TREE_CODE (op) == CONSTRUCTOR
+        && CONSTRUCTOR_NELTS (op) == 0
+        && !TREE_CLOBBER_P (op))
+     || (TREE_CODE (op) == CALL_EXPR
+        && !CALL_EXPR_RETURN_SLOT_OPT (op)))
+    && is_really_empty_class (type);
+}
+
 /* Do C++-specific gimplification.  Args are as for gimplify_expr.  */
 
 int
@@ -597,6 +622,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
        return GS_OK;
       /* Otherwise fall through.  */
     case MODIFY_EXPR:
+    modify_expr_case:
       {
        if (fn_contains_cilk_spawn_p (cfun)
            && cilk_detect_spawn_and_unwrap (expr_p)
@@ -616,31 +642,22 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
          TREE_OPERAND (*expr_p, 1) = build1 (VIEW_CONVERT_EXPR,
                                              TREE_TYPE (op0), op1);
 
-       else if ((is_gimple_lvalue (op1) || INDIRECT_REF_P (op1)
-                 || (TREE_CODE (op1) == CONSTRUCTOR
-                     && CONSTRUCTOR_NELTS (op1) == 0
-                     && !TREE_CLOBBER_P (op1))
-                 || (TREE_CODE (op1) == CALL_EXPR
-                     && !CALL_EXPR_RETURN_SLOT_OPT (op1)))
-                && is_really_empty_class (TREE_TYPE (op0)))
+       else if (simple_empty_class_p (TREE_TYPE (op0), op1))
          {
-           /* Remove any copies of empty classes.  We check that the RHS
-              has a simple form so that TARGET_EXPRs and non-empty
-              CONSTRUCTORs get reduced properly, and we leave the return
-              slot optimization alone because it isn't a copy (FIXME so it
-              shouldn't be represented as one).
-
-              Also drop volatile variables on the RHS to avoid infinite
-              recursion from gimplify_expr trying to load the value.  */
-           if (!TREE_SIDE_EFFECTS (op1))
-             *expr_p = op0;
-           else if (TREE_THIS_VOLATILE (op1)
-                    && (REFERENCE_CLASS_P (op1) || DECL_P (op1)))
-             *expr_p = build2 (COMPOUND_EXPR, TREE_TYPE (*expr_p),
-                               build_fold_addr_expr (op1), op0);
-           else
-             *expr_p = build2 (COMPOUND_EXPR, TREE_TYPE (*expr_p),
-                               op0, op1);
+           /* Remove any copies of empty classes.  Also drop volatile
+              variables on the RHS to avoid infinite recursion from
+              gimplify_expr trying to load the value.  */
+           gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+                          is_gimple_lvalue, fb_lvalue);
+           if (TREE_SIDE_EFFECTS (op1))
+             {
+               if (TREE_THIS_VOLATILE (op1)
+                   && (REFERENCE_CLASS_P (op1) || DECL_P (op1)))
+                 op1 = build_fold_addr_expr (op1);
+
+               gimplify_and_add (op1, pre_p);
+             }
+           *expr_p = TREE_OPERAND (*expr_p, 0);
          }
       }
       ret = GS_OK;
@@ -740,6 +757,19 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
        }
       break;
 
+    case RETURN_EXPR:
+      if (TREE_OPERAND (*expr_p, 0)
+         && (TREE_CODE (TREE_OPERAND (*expr_p, 0)) == INIT_EXPR
+             || TREE_CODE (TREE_OPERAND (*expr_p, 0)) == MODIFY_EXPR))
+       {
+         expr_p = &TREE_OPERAND (*expr_p, 0);
+         code = TREE_CODE (*expr_p);
+         /* Avoid going through the INIT_EXPR case, which can
+            degrade INIT_EXPRs into AGGR_INIT_EXPRs.  */
+         goto modify_expr_case;
+       }
+      /* Fall through.  */
+
     default:
       ret = (enum gimplify_status) c_gimplify_expr (expr_p, pre_p, post_p);
       break;
index 83e060b..e35e484 100644 (file)
@@ -1922,7 +1922,9 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
        {
          /* Per C++11 8.3.6/4, default arguments cannot be added in later
             declarations of a function template.  */
-         check_redeclaration_no_default_args (newdecl);
+         if (DECL_SOURCE_LOCATION (newdecl)
+             != DECL_SOURCE_LOCATION (olddecl))
+           check_redeclaration_no_default_args (newdecl);
 
          check_default_args (newdecl);
 
@@ -11227,11 +11229,10 @@ check_default_argument (tree decl, tree arg, tsubst_flags_t complain)
                                     LOOKUP_IMPLICIT);
   --cp_unevaluated_operand;
 
-  if (warn_zero_as_null_pointer_constant
-      && TYPE_PTR_OR_PTRMEM_P (decl_type)
-      && null_ptr_cst_p (arg)
-      && (complain & tf_warning)
-      && maybe_warn_zero_as_null_pointer_constant (arg, input_location))
+  /* Avoid redundant -Wzero-as-null-pointer-constant warnings at
+     the call sites.  */
+  if (TYPE_PTR_OR_PTRMEM_P (decl_type)
+      && null_ptr_cst_p (arg))
     return nullptr_node;
 
   /* [dcl.fct.default]
index e0b455c..a209ee6 100644 (file)
@@ -8270,8 +8270,23 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
        c_inhibit_evaluation_warnings -= current.lhs == truthvalue_true_node;
 
       if (warn_logical_not_paren
-         && current.lhs_type == TRUTH_NOT_EXPR)
-       warn_logical_not_parentheses (current.loc, current.tree_type, rhs);
+         && TREE_CODE_CLASS (current.tree_type) == tcc_comparison
+         && current.lhs_type == TRUTH_NOT_EXPR
+         /* Avoid warning for !!x == y.  */
+         && (TREE_CODE (current.lhs) != NE_EXPR
+             || !integer_zerop (TREE_OPERAND (current.lhs, 1)))
+         && (TREE_CODE (current.lhs) != TRUTH_NOT_EXPR
+             || (TREE_CODE (TREE_OPERAND (current.lhs, 0)) != TRUTH_NOT_EXPR
+                 /* Avoid warning for !b == y where b is boolean.  */
+                 && (TREE_TYPE (TREE_OPERAND (current.lhs, 0)) == NULL_TREE
+                     || (TREE_CODE (TREE_TYPE (TREE_OPERAND (current.lhs, 0)))
+                         != BOOLEAN_TYPE))))
+         /* Avoid warning for !!b == y where b is boolean.  */
+         && (!DECL_P (current.lhs)
+             || TREE_TYPE (current.lhs) == NULL_TREE
+             || TREE_CODE (TREE_TYPE (current.lhs)) != BOOLEAN_TYPE))
+       warn_logical_not_parentheses (current.loc, current.tree_type,
+                                     maybe_constant_value (rhs));
 
       overload = NULL;
       /* ??? Currently we pass lhs_type == ERROR_MARK and rhs_type ==
@@ -18299,7 +18314,9 @@ parsing_nsdmi (void)
 {
   /* We recognize NSDMI context by the context-less 'this' pointer set up
      by the function above.  */
-  if (current_class_ptr && DECL_CONTEXT (current_class_ptr) == NULL_TREE)
+  if (current_class_ptr
+      && TREE_CODE (current_class_ptr) == PARM_DECL
+      && DECL_CONTEXT (current_class_ptr) == NULL_TREE)
     return true;
   return false;
 }
index 9a00d0d..ea82621 100644 (file)
@@ -20930,7 +20930,13 @@ dependent_type_p_r (tree type)
     return true;
   /* ... or any of the template arguments is a dependent type or
        an expression that is type-dependent or value-dependent.  */
-  else if (TYPE_TEMPLATE_INFO (type)
+  else if (CLASS_TYPE_P (type) && CLASSTYPE_TEMPLATE_INFO (type)
+          && (any_dependent_template_arguments_p
+              (INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type)))))
+    return true;
+  /* For an alias template specialization, check the arguments both to the
+     class template and the alias template.  */
+  else if (alias_template_specialization_p (type)
           && (any_dependent_template_arguments_p
               (INNERMOST_TEMPLATE_ARGS (TYPE_TI_ARGS (type)))))
     return true;
index eb81861..91b94f7 100644 (file)
@@ -786,26 +786,6 @@ evaluated only once when using @code{__auto_type}, but twice if
 @code{typeof} is used.
 @end itemize
 
-@emph{Compatibility Note:} In addition to @code{typeof}, GCC 2 supported
-a more limited extension that permitted one to write
-
-@smallexample
-typedef @var{T} = @var{expr};
-@end smallexample
-
-@noindent
-with the effect of declaring @var{T} to have the type of the expression
-@var{expr}.  This extension does not work with GCC 3 (versions between
-3.0 and 3.2 crash; 3.2.1 and later give an error).  Code that
-relies on it should be rewritten to use @code{typeof}:
-
-@smallexample
-typedef typeof(@var{expr}) @var{T};
-@end smallexample
-
-@noindent
-This works with all versions of GCC@.
-
 @node Conditionals
 @section Conditionals with Omitted Operands
 @cindex conditional expressions, extensions
@@ -1498,16 +1478,13 @@ structure or an element of an array.  (However, these uses are
 permitted by GCC as extensions.)
 @end itemize
 
-GCC versions before 3.0 allowed zero-length arrays to be statically
-initialized, as if they were flexible arrays.  In addition to those
-cases that were useful, it also allowed initializations in situations
-that would corrupt later data.  Non-empty initialization of zero-length
-arrays is now treated like any case where there are more initializer
+Non-empty initialization of zero-length
+arrays is treated like any case where there are more initializer
 elements than the array holds, in that a suitable warning about ``excess
 elements in array'' is given, and the excess elements (all of them, in
 this case) are ignored.
 
-Instead GCC allows static initialization of flexible array members.
+GCC allows static initialization of flexible array members.
 This is equivalent to defining a new structure containing the original
 structure followed by an array of sufficient size to contain the data.
 E.g.@: in the following, @code{f1} is constructed as if it were declared
@@ -1729,9 +1706,10 @@ argument, these arguments are not macro expanded.
 @cindex escaped newlines
 @cindex newlines (escaped)
 
-Recently, the preprocessor has relaxed its treatment of escaped
-newlines.  Previously, the newline had to immediately follow a
-backslash.  The current implementation allows whitespace in the form
+The preprocessor treatment of escaped newlines is more relaxed 
+than that specified by the C90 standard, which requires the newline
+to immediately follow a backslash.  
+GCC's implementation allows whitespace in the form
 of spaces, horizontal and vertical tabs, and form feeds between the
 backslash and the subsequent newline.  The preprocessor issues a
 warning, but treats it as a valid escaped newline and combines the two
@@ -1905,12 +1883,12 @@ In C, a compound literal designates an unnamed object with static or
 automatic storage duration.  In C++, a compound literal designates a
 temporary object, which only lives until the end of its
 full-expression.  As a result, well-defined C code that takes the
-address of a subobject of a compound literal can be undefined in C++.
+address of a subobject of a compound literal can be undefined in C++,
+so the C++ compiler rejects the conversion of a temporary array to a pointer.
 For instance, if the array compound literal example above appeared
 inside a function, any subsequent use of @samp{foo} in C++ has
 undefined behavior because the lifetime of the array ends after the
-declaration of @samp{foo}.  As a result, the C++ compiler now rejects
-the conversion of a temporary array to a pointer.
+declaration of @samp{foo}.  
 
 As an optimization, the C++ compiler sometimes gives array compound
 literals longer lifetimes: when the array either appears outside a
@@ -2447,21 +2425,6 @@ function that calls a non-@code{const} function usually must not be
 @code{const}.  It does not make sense for a @code{const} function to
 return @code{void}.
 
-The attribute @code{const} is not implemented in GCC versions earlier
-than 2.5.  An alternative way to declare that a function has no side
-effects, which works in the current version and in some older versions,
-is as follows:
-
-@smallexample
-typedef int intfn ();
-
-extern const intfn square;
-@end smallexample
-
-@noindent
-This approach does not work in GNU C++ from 2.6.0 on, since the language
-specifies that the @samp{const} must be attached to the return value.
-
 @item constructor
 @itemx destructor
 @itemx constructor (@var{priority})
@@ -2536,14 +2499,13 @@ On systems that support the @code{visibility} attribute, this
 attribute also implies ``default'' visibility.  It is an error to
 explicitly specify any other visibility.
 
-In previous versions of GCC, the @code{dllexport} attribute was ignored
-for inlined functions, unless the @option{-fkeep-inline-functions} flag
-had been used.  The default behavior now is to emit all dllexported
-inline functions; however, this can cause object file-size bloat, in
-which case the old behavior can be restored by using
-@option{-fno-keep-inline-dllexport}.
+GCC's default behavior is to emit all inline functions with the
+@code{dllexport} attribute.  Since this can cause object file-size bloat,
+you can use @option{-fno-keep-inline-dllexport}, which tells GCC to
+ignore the attribute for inlined functions unless the 
+@option{-fkeep-inline-functions} flag is used instead.
 
-The attribute is also ignored for undefined symbols.
+The attribute is ignored for undefined symbols.
 
 When applied to C++ classes, the attribute marks defined non-inlined
 member functions and static data members as exports.  Static consts
@@ -2595,8 +2557,7 @@ the current translation unit.
 For Microsoft Windows targets the use of the @code{dllimport}
 attribute on functions is not necessary, but provides a small
 performance benefit by eliminating a thunk in the DLL@.  The use of the
-@code{dllimport} attribute on imported variables was required on older
-versions of the GNU linker, but can now be avoided by passing the
+@code{dllimport} attribute on imported variables can be avoided by passing the
 @option{--enable-auto-import} switch to the GNU linker.  As with
 functions, using the attribute for a variable eliminates a thunk in
 the DLL@.
@@ -2931,8 +2892,8 @@ void *memcpy (void *, const void *, size_t)
      __attribute__ ((ifunc ("resolve_memcpy")));
 @end smallexample
 
-Indirect functions cannot be weak, and require a recent binutils (at
-least version 2.20.1), and GNU C library (at least version 2.11.1).
+Indirect functions cannot be weak.  Binutils version 2.20.1 or higher
+and GNU C Library version 2.11.1 are required to use this feature.
 
 @item interrupt
 @cindex interrupt handler functions
@@ -3573,28 +3534,13 @@ restored before calling the @code{noreturn} function.
 It does not make sense for a @code{noreturn} function to have a return
 type other than @code{void}.
 
-The attribute @code{noreturn} is not implemented in GCC versions
-earlier than 2.5.  An alternative way to declare that a function does
-not return, which works in the current version and in some older
-versions, is as follows:
-
-@smallexample
-typedef void voidfn ();
-
-volatile voidfn fatal;
-@end smallexample
-
-@noindent
-This approach does not work in GNU C++.
-
 @item nothrow
 @cindex @code{nothrow} function attribute
 The @code{nothrow} attribute is used to inform the compiler that a
 function cannot throw an exception.  For example, most functions in
 the standard C library can be guaranteed not to throw an exception
 with the notable exceptions of @code{qsort} and @code{bsearch} that
-take function pointer arguments.  The @code{nothrow} attribute is not
-implemented in GCC versions earlier than 3.3.
+take function pointer arguments.
 
 @item nosave_low_regs
 @cindex @code{nosave_low_regs} attribute
@@ -3692,9 +3638,6 @@ Interesting non-pure functions are functions with infinite loops or those
 depending on volatile memory or other system resource, that may change between
 two consecutive calls (such as @code{feof} in a multithreading environment).
 
-The attribute @code{pure} is not implemented in GCC versions earlier
-than 2.96.
-
 @item hot
 @cindex @code{hot} function attribute
 The @code{hot} attribute on a function is used to inform the compiler that
@@ -3706,9 +3649,6 @@ improving locality.
 When profile feedback is available, via @option{-fprofile-use}, hot functions
 are automatically detected and this attribute is ignored.
 
-The @code{hot} attribute on functions is not implemented in GCC versions
-earlier than 4.3.
-
 @item cold
 @cindex @code{cold} function attribute
 The @code{cold} attribute on functions is used to inform the compiler that
@@ -3724,9 +3664,6 @@ of hot functions that do call marked functions in rare occasions.
 When profile feedback is available, via @option{-fprofile-use}, cold functions
 are automatically detected and this attribute is ignored.
 
-The @code{cold} attribute on functions is not implemented in GCC versions
-earlier than 4.3.
-
 @item no_sanitize_address
 @itemx no_address_safety_analysis
 @cindex @code{no_sanitize_address} function attribute
@@ -4660,9 +4597,6 @@ the path following the label is more likely than paths that are not so
 annotated.  This attribute is used in cases where @code{__builtin_expect}
 cannot be used, for instance with computed goto or @code{asm goto}.
 
-The @code{hot} attribute on labels is not implemented in GCC versions
-earlier than 4.8.
-
 @item cold
 @cindex @code{cold} label attribute
 The @code{cold} attribute on labels is used to inform the compiler that
@@ -4670,9 +4604,6 @@ the path following the label is unlikely to be executed.  This attribute
 is used in cases where @code{__builtin_expect} cannot be used, for instance
 with computed goto or @code{asm goto}.
 
-The @code{cold} attribute on labels is not implemented in GCC versions
-earlier than 4.8.
-
 @end table
 
 @node Attribute Syntax
@@ -5985,7 +5916,7 @@ main (void)
 If you replaced @code{short_a} with @code{short} in the variable
 declaration, the above program would abort when compiled with
 @option{-fstrict-aliasing}, which is on by default at @option{-O2} or
-above in recent GCC versions.
+above.
 
 @item visibility
 In C++, attribute visibility (@pxref{Function Attributes}) can also be
@@ -7845,21 +7776,8 @@ static const char __func__[] = "function-name";
 appeared, where function-name is the name of the lexically-enclosing
 function.  This name is the unadorned name of the function.
 
-@code{__FUNCTION__} is another name for @code{__func__}.  Older
-versions of GCC recognize only this name.  However, it is not
-standardized.  For maximum portability, we recommend you use
-@code{__func__}, but provide a fallback definition with the
-preprocessor:
-
-@smallexample
-#if __STDC_VERSION__ < 199901L
-# if __GNUC__ >= 2
-#  define __func__ __FUNCTION__
-# else
-#  define __func__ "<unknown>"
-# endif
-#endif
-@end smallexample
+@code{__FUNCTION__} is another name for @code{__func__}, provided for
+backward compatibility with old versions of GCC.
 
 In C, @code{__PRETTY_FUNCTION__} is yet another name for
 @code{__func__}.  However, in C++, @code{__PRETTY_FUNCTION__} contains
@@ -7897,13 +7815,9 @@ __FUNCTION__ = sub
 __PRETTY_FUNCTION__ = void a::sub(int)
 @end smallexample
 
-These identifiers are not preprocessor macros.  In GCC 3.3 and
-earlier, in C only, @code{__FUNCTION__} and @code{__PRETTY_FUNCTION__}
-were treated as string literals; they could be used to initialize
-@code{char} arrays, and they could be concatenated with other string
-literals.  GCC 3.4 and later treat them as variables, like
-@code{__func__}.  In C++, @code{__FUNCTION__} and
-@code{__PRETTY_FUNCTION__} have always been variables.
+These identifiers are variables, not preprocessor macros, and may not
+be used to initialize @code{char} arrays or be concatenated with other string
+literals.
 
 @node Return Address
 @section Getting the Return or Frame Address of a Function
@@ -9718,10 +9632,6 @@ not otherwise permitted in a static initializer (for example,
 @code{0 && foo ()}).  GCC must be more conservative about evaluating the
 built-in in this case, because it has no opportunity to perform
 optimization.
-
-Previous versions of GCC did not accept this built-in in data
-initializers.  The earliest version where it is completely safe is
-3.0.1.
 @end deftypefn
 
 @deftypefn {Built-in Function} long __builtin_expect (long @var{exp}, long @var{c})
@@ -17894,9 +17804,6 @@ if @code{attribute((optimize("STRING")))} was specified for that
 function.  The parenthesis around the options is optional.
 @xref{Function Attributes}, for more information about the
 @code{optimize} attribute and the attribute syntax.
-
-The @samp{#pragma GCC optimize} pragma is not implemented in GCC
-versions earlier than 4.4.
 @end table
 
 @table @code
@@ -17910,9 +17817,6 @@ options.  It is intended for include files where you temporarily want
 to switch to using a different @samp{#pragma GCC target} or
 @samp{#pragma GCC optimize} and then to pop back to the previous
 options.
-
-The @samp{#pragma GCC push_options} and @samp{#pragma GCC pop_options}
-pragmas are not implemented in GCC versions earlier than 4.4.
 @end table
 
 @table @code
@@ -17922,9 +17826,6 @@ pragmas are not implemented in GCC versions earlier than 4.4.
 This pragma clears the current @code{#pragma GCC target} and
 @code{#pragma GCC optimize} to use the default switches as specified
 on the command line.
-
-The @samp{#pragma GCC reset_options} pragma is not implemented in GCC
-versions earlier than 4.4.
 @end table
 
 @node Loop-Specific Pragmas
@@ -18557,14 +18458,11 @@ user with a way of explicitly directing the compiler to emit entities
 with vague linkage (and debugging information) in a particular
 translation unit.
 
-@emph{Note:} As of GCC 2.7.2, these @code{#pragma}s are not useful in
-most cases, because of COMDAT support and the ``key method'' heuristic
+@emph{Note:} These @code{#pragma}s have been superceded as of GCC 2.7.2
+by COMDAT support and the ``key method'' heuristic
 mentioned in @ref{Vague Linkage}.  Using them can actually cause your
 program to grow due to unnecessary out-of-line copies of inline
-functions.  Currently (3.4) the only benefit of these
-@code{#pragma}s is reduced duplication of debugging information, and
-that should be addressed soon on DWARF 2 targets with the use of
-COMDAT groups.
+functions.
 
 @table @code
 @item #pragma interface
@@ -18608,12 +18506,6 @@ file.  For example, in @file{allclass.cc}, giving just
 @samp{#pragma implementation}
 by itself is equivalent to @samp{#pragma implementation "allclass.h"}.
 
-In versions of GNU C++ prior to 2.6.0 @file{allclass.h} was treated as
-an implementation file whenever you would include it from
-@file{allclass.cc} even if you never specified @samp{#pragma
-implementation}.  This was deemed to be more trouble than it was worth,
-however, and disabled.
-
 Use the string argument if you want a single implementation file to
 include code from multiple header files.  (You must also use
 @samp{#include} to include the header file; @samp{#pragma
index 67814d4..08ce074 100644 (file)
@@ -302,6 +302,15 @@ Objective-C and Objective-C++ Dialects}.
 @gccoptlist{-d@var{letters}  -dumpspecs  -dumpmachine  -dumpversion @gol
 -fsanitize=@var{style} -fsanitize-recover -fsanitize-recover=@var{style} @gol
 -fasan-shadow-offset=@var{number} -fsanitize-undefined-trap-on-error @gol
+-fcheck-pointer-bounds -fchkp-check-incomplete-type @gol
+-fchkp-first-field-has-own-bounds -fchkp-narrow-bounds @gol
+-fchkp-narrow-to-innermost-array -fchkp-optimize @gol
+-fchkp-use-fast-string-functions -fchkp-use-nochk-string-functions @gol
+-fchkp-use-static-bounds -fchkp-use-static-const-bounds @gol
+-fchkp-treat-zero-dynamic-size-as-infinite -fchkp-check-read @gol
+-fchkp-check-read -fchkp-check-write -fchkp-store-bounds @gol
+-fchkp-instrument-calls -fchkp-instrument-marked-only @gol
+-fchkp-use-wrappers @gol
 -fdbg-cnt-list -fdbg-cnt=@var{counter-value-list} @gol
 -fdisable-ipa-@var{pass_name} @gol
 -fdisable-rtl-@var{pass_name} @gol
@@ -477,6 +486,7 @@ Objective-C and Objective-C++ Dialects}.
 -nostartfiles  -nodefaultlibs  -nostdlib -pie -rdynamic @gol
 -s  -static -static-libgcc -static-libstdc++ @gol
 -static-libasan -static-libtsan -static-liblsan -static-libubsan @gol
+-static-libmpx -static-libmpxwrappers @gol
 -shared -shared-libgcc  -symbolic @gol
 -T @var{script}  -Wl,@var{option}  -Xlinker @var{option} @gol
 -u @var{symbol} -z @var{keyword}}
@@ -561,8 +571,8 @@ Objective-C and Objective-C++ Dialects}.
 
 @emph{AVR Options}
 @gccoptlist{-mmcu=@var{mcu} -maccumulate-args -mbranch-cost=@var{cost} @gol
--mcall-prologues -mint8 -mno-interrupts -mrelax @gol
--mstrict-X -mtiny-stack -Waddr-space-convert}
+-mcall-prologues -mint8 -mn_flash=@var{size} -mno-interrupts @gol
+-mrelax -mrmw -mstrict-X -mtiny-stack -Waddr-space-convert}
 
 @emph{Blackfin Options}
 @gccoptlist{-mcpu=@var{cpu}@r{[}-@var{sirevision}@r{]} @gol
@@ -1767,17 +1777,15 @@ releases.
 @opindex fgnu89-inline
 The option @option{-fgnu89-inline} tells GCC to use the traditional
 GNU semantics for @code{inline} functions when in C99 mode.
-@xref{Inline,,An Inline Function is As Fast As a Macro}.  This option
-is accepted and ignored by GCC versions 4.1.3 up to but not including
-4.3.  In GCC versions 4.3 and later it changes the behavior of GCC in
-C99 mode.  Using this option is roughly equivalent to adding the
+@xref{Inline,,An Inline Function is As Fast As a Macro}.
+Using this option is roughly equivalent to adding the
 @code{gnu_inline} function attribute to all inline functions
 (@pxref{Function Attributes}).
 
 The option @option{-fno-gnu89-inline} explicitly tells GCC to use the
 C99 semantics for @code{inline} when in C99 or gnu99 mode (i.e., it
-specifies the default behavior).  This option was first supported in
-GCC 4.3.  This option is not supported in @option{-std=c90} or
+specifies the default behavior).  
+This option is not supported in @option{-std=c90} or
 @option{-std=gnu90} mode.
 
 The preprocessor macros @code{__GNUC_GNU_INLINE__} and
@@ -2112,7 +2120,7 @@ See also @option{-Wabi}.
 
 @item -fabi-compat-version=@var{n}
 @opindex fabi-compat-version
-Starting with GCC 4.5, on targets that support strong aliases, G++
+On targets that support strong aliases, G++
 works around mangling changes by creating an alias with the correct
 mangled name when defining a symbol with an incorrect mangled name.
 This switch specifies which ABI version to use for the alias.
@@ -2173,11 +2181,10 @@ deprecated, and may be removed in a future version of G++.
 Inject friend functions into the enclosing namespace, so that they are
 visible outside the scope of the class in which they are declared.
 Friend functions were documented to work this way in the old Annotated
-C++ Reference Manual, and versions of G++ before 4.1 always worked
-that way.  However, in ISO C++ a friend function that is not declared
+C++ Reference Manual.  
+However, in ISO C++ a friend function that is not declared
 in an enclosing scope can only be found using argument dependent
-lookup.  This option causes friends to be injected as they were in
-earlier releases.
+lookup.  GCC defaults to the standard behavior.
 
 This option is for compatibility, and may be removed in a future
 release of G++.
@@ -4536,8 +4543,7 @@ except when the same as the default promotion.
 @opindex Wno-declaration-after-statement
 Warn when a declaration is found after a statement in a block.  This
 construct, known from C++, was introduced with ISO C99 and is by default
-allowed in GCC@.  It is not supported by ISO C90 and was not supported by
-GCC versions before GCC 3.0.  @xref{Mixed Declarations}.
+allowed in GCC@.  It is not supported by ISO C90.  @xref{Mixed Declarations}.
 
 @item -Wundef
 @opindex Wundef
@@ -5827,6 +5833,135 @@ a @code{libubsan} library routine.  The advantage of this is that the
 @code{libubsan} library is not needed and is not linked in, so this
 is usable even in freestanding environments.
 
+@item -fcheck-pointer-bounds
+@opindex fcheck-pointer-bounds
+@opindex fno-check-pointer-bounds
+Enable Pointer Bounds Checker instrumentation.  Each memory reference
+is instrumented with checks of pointer used for memory access against
+bounds associated with that pointer.  Generated instrumentation may
+be controlled by various @option{-fchkp-*} options.  Currently there
+is only Intel MPX based implementation available, thus i386 target
+and @option{-mmpx} are required.  MPX based instrumentation requires
+a runtime library to enable MPX in a hardware and handle bounds
+violation signals.  By default when @option{-fcheck-pointer-bounds}
+and @option{-mmpx} options are used to link a program, the GCC driver
+links against @option{libmpx} runtime library.  MPX based instrumentation
+may be used for a debugging and also it may be included into a release
+version to increase program security.  Depending on usage you may
+put different requirements to runtime library.  Current version
+ of MPX runtime library is more oriented to be used as a debugging
+tool.  MPX runtime library usage implies @option{-lpthread}.  See
+also @option{-static-libmpx}.  The runtime library  behavior can be
+influenced using various @env{CHKP_RT_*} environment variables.  See
+@uref{https://gcc.gnu.org/wiki/Intel%20MPX%20support%20in%20the%20GCC%20compiler}
+for more details.
+
+@item -fchkp-check-incomplete-type
+@opindex fchkp-check-incomplete-type
+@opindex fno-chkp-check-incomplete-type
+Generate pointer bounds checks for variables with incomplete type.
+Enabled by default
+
+@item -fchkp-narrow-bounds
+@opindex fchkp-narrow-bounds
+@opindex fno-chkp-narrow-bounds
+Controls bounds used by Pointer Bounds Checker for pointers to object
+fields.  If narrowing is enabled then field bounds are used.  Otherwise
+object bounds are used.  See also @option{-fchkp-narrow-to-innermost-array}
+and @option{-fchkp-first-field-has-own-bounds}.  Enabled by default.
+
+@item -fchkp-first-field-has-own-bounds
+@opindex fchkp-first-field-has-own-bounds
+@opindex fno-chkp-first-field-has-own-bounds
+Forces Pointer Bounds Checker to use narrowed bounds for address of the
+first field in the structure.  By default pointer to the first field has
+the same bounds as pointer to the whole structure.
+
+@item -fchkp-narrow-to-innermost-array
+@opindex fchkp-narrow-to-innermost-array
+@opindex fno-chkp-narrow-to-innermost-array
+Forces Pointer Bounds Checker to use bounds of the innermost arrays in
+case of nested static arryas access.  By default it is disabled and
+bounds of the outermost array are used.
+
+@item -fchkp-optimize
+@opindex fchkp-optimize
+@opindex fno-chkp-optimize
+Enables Pointer Bounds Checker optimizations.  Enabled by default at
+optimization levels @option{-O}, @option{-O2}, @option{-O3}.
+
+@item -fchkp-use-fast-string-functions
+@opindex fchkp-use-fast-string-functions
+@opindex fno-chkp-use-fast-string-functions
+Allow to use @code{*_nobnd} versions of string functions (not copying bounds)
+by Pointer Bounds Checker.  Disabled by default.
+
+@item -fchkp-use-nochk-string-functions
+@opindex fchkp-use-nochk-string-functions
+@opindex fno-chkp-use-nochk-string-functions
+Allow to use @code{*_nochk} versions of string functions (not checking bounds)
+by Pointer Bounds Checker.  Disabled by default.
+
+@item -fchkp-use-static-bounds
+@opindex fchkp-use-static-bounds
+@opindex fno-chkp-use-static-bounds
+Allow Pointer Bounds Checker to generate static bounds holding
+bounds of static variables.  Enabled by default.
+
+@item -fchkp-use-static-const-bounds
+@opindex fchkp-use-static-const-bounds
+@opindex fno-chkp-use-static-const-bounds
+Use statically initialized bounds for constant bounds instead of
+generating them each time it is required.  By default enabled when
+@option{-fchkp-use-static-bounds} is enabled.
+
+@item -fchkp-treat-zero-dynamic-size-as-infinite
+@opindex fchkp-treat-zero-dynamic-size-as-infinite
+@opindex fno-chkp-treat-zero-dynamic-size-as-infinite
+With this option zero size obtained dynamically for objects with
+incomplete type will be treated as infinite by Pointer Bounds
+Checker.  It may be helpful if program is linked with a library
+missing size information for some symbols.  Disabled by default.
+
+@item -fchkp-check-read
+@opindex fchkp-check-read
+@opindex fno-chkp-check-read
+Instructs Pointer Bounds Checker to generate checks for all read
+accesses to memory.  Enabled by default.
+
+@item -fchkp-check-write
+@opindex fchkp-check-write
+@opindex fno-chkp-check-write
+Instructs Pointer Bounds Checker to generate checks for all write
+accesses to memory.  Enabled by default.
+
+@item -fchkp-store-bounds
+@opindex fchkp-store-bounds
+@opindex fno-chkp-store-bounds
+Instructs Pointer Bounds Checker to generate bounds stores for
+pointer writes.  Enabled by default.
+
+@item -fchkp-instrument-calls
+@opindex fchkp-instrument-calls
+@opindex fno-chkp-instrument-calls
+Instructs Pointer Bounds Checker to pass pointer bounds to calls.
+Enabled by default.
+
+@item -fchkp-instrument-marked-only
+@opindex fchkp-instrument-marked-only
+@opindex fno-chkp-instrument-marked-only
+Instructs Pointer Bounds Checker to instrument only functions
+marked with @code{bnd_instrument} attribute.  Disabled by default.
+
+@item -fchkp-use-wrappers
+@opindex fchkp-use-wrappers
+@opindex fno-chkp-use-wrappers
+Allows Pointer Bounds Checker to replace calls to built-in function
+with calls to wrapper functions.  When the @option{-fchkp-use-wrappers}
+is used to link a program, the GCC driver automatically links
+agains @option{libmpxwrappers}.  See also @option{-static-libmpxwrappers}.
+Enabled by default.
+
 @item -fdump-final-insns@r{[}=@var{file}@r{]}
 @opindex fdump-final-insns
 Dump the final internal representation (RTL) to @var{file}.  If the
@@ -7455,11 +7590,10 @@ machine-description macro @code{FRAME_POINTER_REQUIRED} controls
 whether a target machine supports this flag.  @xref{Registers,,Register
 Usage, gccint, GNU Compiler Collection (GCC) Internals}.
 
-Starting with GCC version 4.6, the default setting (when not optimizing for
-size) for 32-bit GNU/Linux x86 and 32-bit Darwin x86 targets has been changed to
-@option{-fomit-frame-pointer}.  The default can be reverted to
-@option{-fno-omit-frame-pointer} by configuring GCC with the
-@option{--enable-frame-pointer} configure option.
+The default setting (when not optimizing for
+size) for 32-bit GNU/Linux x86 and 32-bit Darwin x86 targets is
+@option{-fomit-frame-pointer}.  You can configure GCC with the
+@option{--enable-frame-pointer} configure option to change the default.
 
 Enabled at levels @option{-O}, @option{-O2}, @option{-O3}, @option{-Os}.
 
@@ -8681,8 +8815,7 @@ from other functions.  It is a more limited form of
 @option{-ftree-coalesce-vars}.  This may harm debug information of such
 inlined variables, but it keeps variables of the inlined-into
 function apart from each other, such that they are more likely to
-contain the expected values in a debugging session.  This was the
-default in GCC versions older than 4.7.
+contain the expected values in a debugging session.
 
 @item -ftree-coalesce-vars
 @opindex ftree-coalesce-vars
@@ -11136,6 +11269,27 @@ option is not used, then this links against the shared version of
 driver to link @file{libubsan} statically, without necessarily linking
 other libraries statically.
 
+@item -static-libmpx
+@opindex static-libmpx
+When @option{-fcheck-pointer bounds} and @option{-mmpx} options are
+used to link a program, the GCC driver automatically links against
+@option{libmpx}.  If @file{libmpx} is available as a shared library,
+and the @option{-static} option is not used, then this links against
+the shared version of @file{libmpx}.  The @option{-static-libmpx}
+option directs the GCC driver to link @file{libmpx} statically,
+without necessarily linking other libraries statically.
+
+@item -static-libmpxwrappers
+@opindex static-libmpxwrappers
+When @option{-fcheck-pointer bounds}, @option{-mmpx} options are used and
+@option{-fno-chkp-use-wrappers} option is not used to link a program, the
+GCC driver automatically links against @option{libmpxwrappers}.  If
+@file{libmpxwrappers} is available as a shared library, and the
+@option{-static} option is not used, then this links against the shared
+version of @file{libmpxwrappers}.  The @option{-static-libmpxwrappers}
+option directs the GCC driver to link @file{libmpxwrappers} statically,
+without necessarily linking other libraries statically.
+
 @item -static-libstdc++
 @opindex static-libstdc++
 When the @command{g++} program is used to link a C++ program, it
@@ -13349,6 +13503,11 @@ and @code{long long} is 4 bytes.  Please note that this option does not
 conform to the C standards, but it results in smaller code
 size.
 
+@item -mn-flash=@var{num}
+@opindex mn-flash
+Assume that the flash memory has a size of 
+@var{num} times 64@tie{}KiB.
+
 @item -mno-interrupts
 @opindex mno-interrupts
 Generated code is not compatible with hardware interrupts.
@@ -13358,8 +13517,9 @@ Code size is smaller.
 @opindex mrelax
 Try to replace @code{CALL} resp.@: @code{JMP} instruction by the shorter
 @code{RCALL} resp.@: @code{RJMP} instruction if applicable.
-Setting @option{-mrelax} just adds the @option{--relax} option to the
-linker command line when the linker is called.
+Setting @option{-mrelax} just adds the @option{--mlink-relax} option to
+the assembler's command line and the @option{--relax} option to the
+linker's command line.
 
 Jump relaxing is performed by the linker because jump offsets are not
 known before code is located. Therefore, the assembler code generated by the
@@ -13369,6 +13529,11 @@ differ from instructions in the assembler code.
 Relaxing must be turned on if linker stubs are needed, see the
 section on @code{EIND} and linker stubs below.
 
+@item -mrmw
+@opindex mrmw
+Assume that the device supports the Read-Modify-Write
+instructions @code{XCH}, @code{LAC}, @code{LAS} and @code{LAT}.
+
 @item -msp8
 @opindex msp8
 Treat the stack pointer register as an 8-bit register,
@@ -13609,13 +13774,18 @@ architecture and depends on the @option{-mmcu=@var{mcu}} option.
 Possible values are:
 
 @code{2}, @code{25}, @code{3}, @code{31}, @code{35},
-@code{4}, @code{5}, @code{51}, @code{6}, @code{102}, @code{104},
+@code{4}, @code{5}, @code{51}, @code{6}
+
+for @var{mcu}=@code{avr2}, @code{avr25}, @code{avr3}, @code{avr31},
+@code{avr35}, @code{avr4}, @code{avr5}, @code{avr51}, @code{avr6},
+
+respectively and
+
+@code{100}, @code{102}, @code{104},
 @code{105}, @code{106}, @code{107}
 
-for @var{mcu}=@code{avr2}, @code{avr25}, @code{avr3},
-@code{avr31}, @code{avr35}, @code{avr4}, @code{avr5}, @code{avr51},
-@code{avr6}, @code{avrxmega2}, @code{avrxmega4}, @code{avrxmega5},
-@code{avrxmega6}, @code{avrxmega7}, respectively.
+for @var{mcu}=@code{avrtiny}, @code{avrxmega2}, @code{avrxmega4},
+@code{avrxmega5}, @code{avrxmega6}, @code{avrxmega7}, respectively.
 If @var{mcu} specifies a device, this built-in macro is set
 accordingly. For example, with @option{-mmcu=atmega8} the macro is
 defined to @code{4}.
@@ -13635,7 +13805,7 @@ the device name as from the AVR user manual. The difference between
 If @var{device} is not a device but only a core architecture like
 @samp{avr51}, this macro is not defined.
 
-@item   __AVR_DEVICE_NAME__
+@item __AVR_DEVICE_NAME__
 Setting @option{-mmcu=@var{device}} defines this built-in macro to
 the device's name. For example, with @option{-mmcu=atmega8} the macro
 is defined to @code{atmega8}.
@@ -19982,7 +20152,7 @@ The default is to not print debug information.
 Generate code that runs on @var{cpu-type}, which is the name of a system
 representing a certain processor type.  Possible values for
 @var{cpu-type} are @samp{g5}, @samp{g6}, @samp{z900}, @samp{z990},
-@samp{z9-109}, @samp{z9-ec} and @samp{z10}.
+@samp{z9-109}, @samp{z9-ec}, @samp{z10},  @samp{z196}, and @samp{zEC12}.
 When generating code using the instructions available on z/Architecture,
 the default is @option{-march=z900}.  Otherwise, the default is
 @option{-march=g5}.
@@ -20046,9 +20216,9 @@ The @var{stack-guard} option can only be used in conjunction with @var{stack-siz
 If the hotpatch option is enabled, a ``hot-patching'' function
 prologue is generated for all functions in the compilation unit.
 The funtion label is prepended with the given number of two-byte
-Nop instructions (@var{pre-halfwords}, maximum 1000000).  After
+NOP instructions (@var{pre-halfwords}, maximum 1000000).  After
 the label, 2 * @var{post-halfwords} bytes are appended, using the
-larges nop like instructions the architecture allows (maximum
+largest NOP like instructions the architecture allows (maximum
 1000000).
 
 If both arguments are zero, hotpatching is disabled.
@@ -23638,9 +23808,7 @@ available to be linked against from outside the shared object.
 @samp{protected} and @samp{internal} are pretty useless in real-world
 usage so the only other commonly used option is @samp{hidden}.
 The default if @option{-fvisibility} isn't specified is
-@samp{default}, i.e., make every
-symbol public---this causes the same behavior as previous versions of
-GCC@.
+@samp{default}, i.e., make every symbol public.
 
 A good explanation of the benefits offered by ensuring ELF
 symbols have the correct visibility is given by ``How To Write
index 33d4ae4..09c8c90 100644 (file)
@@ -982,7 +982,7 @@ nearest_common_dominator_for_set (enum cdi_direction dir, bitmap blocks)
 
    A_Dominated_by_B (node A, node B)
    {
-     return DFS_Number_In(A) >= DFS_Number_In(A)
+     return DFS_Number_In(A) >= DFS_Number_In(B)
             && DFS_Number_Out (A) <= DFS_Number_Out(B);
    }  */
 
index 0834d47..6d085b1 100644 (file)
@@ -2860,7 +2860,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
       case ADDR_EXPR:
        return operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0),
                                TREE_CONSTANT (arg0) && TREE_CONSTANT (arg1)
-                               ? OEP_CONSTANT_ADDRESS_OF : 0);
+                               ? OEP_CONSTANT_ADDRESS_OF | OEP_ADDRESS_OF : 0);
       default:
        break;
       }
@@ -2922,7 +2922,11 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
       switch (TREE_CODE (arg0))
        {
        case INDIRECT_REF:
-         flags &= ~OEP_CONSTANT_ADDRESS_OF;
+         if (!(flags & OEP_ADDRESS_OF)
+             && (TYPE_ALIGN (TREE_TYPE (arg0))
+                 != TYPE_ALIGN (TREE_TYPE (arg1))))
+           return 0;
+         flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF);
          return OP_SAME (0);
 
        case REALPART_EXPR:
@@ -2930,30 +2934,35 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
          return OP_SAME (0);
 
        case TARGET_MEM_REF:
-         flags &= ~OEP_CONSTANT_ADDRESS_OF;
-         /* Require equal extra operands and then fall through to MEM_REF
-            handling of the two common operands.  */
-         if (!OP_SAME_WITH_NULL (2)
-             || !OP_SAME_WITH_NULL (3)
-             || !OP_SAME_WITH_NULL (4))
-           return 0;
-         /* Fallthru.  */
        case MEM_REF:
-         flags &= ~OEP_CONSTANT_ADDRESS_OF;
          /* Require equal access sizes, and similar pointer types.
             We can have incomplete types for array references of
             variable-sized arrays from the Fortran frontend
             though.  Also verify the types are compatible.  */
-         return ((TYPE_SIZE (TREE_TYPE (arg0)) == TYPE_SIZE (TREE_TYPE (arg1))
+         if (!((TYPE_SIZE (TREE_TYPE (arg0)) == TYPE_SIZE (TREE_TYPE (arg1))
                   || (TYPE_SIZE (TREE_TYPE (arg0))
                       && TYPE_SIZE (TREE_TYPE (arg1))
                       && operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)),
                                           TYPE_SIZE (TREE_TYPE (arg1)), flags)))
                  && types_compatible_p (TREE_TYPE (arg0), TREE_TYPE (arg1))
-                 && alias_ptr_types_compatible_p
-                      (TREE_TYPE (TREE_OPERAND (arg0, 1)),
-                       TREE_TYPE (TREE_OPERAND (arg1, 1)))
-                 && OP_SAME (0) && OP_SAME (1));
+                 && ((flags & OEP_ADDRESS_OF)
+                     || (alias_ptr_types_compatible_p
+                           (TREE_TYPE (TREE_OPERAND (arg0, 1)),
+                            TREE_TYPE (TREE_OPERAND (arg1, 1)))
+                         && (MR_DEPENDENCE_CLIQUE (arg0)
+                             == MR_DEPENDENCE_CLIQUE (arg1))
+                         && (MR_DEPENDENCE_BASE (arg0)
+                             == MR_DEPENDENCE_BASE (arg1))
+                         && (TYPE_ALIGN (TREE_TYPE (arg0))
+                           == TYPE_ALIGN (TREE_TYPE (arg1)))))))
+           return 0;
+         flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF);
+         return (OP_SAME (0) && OP_SAME (1)
+                 /* TARGET_MEM_REF require equal extra operands.  */
+                 && (TREE_CODE (arg0) != TARGET_MEM_REF
+                     || (OP_SAME_WITH_NULL (2)
+                         && OP_SAME_WITH_NULL (3)
+                         && OP_SAME_WITH_NULL (4))));
 
        case ARRAY_REF:
        case ARRAY_RANGE_REF:
@@ -2962,7 +2971,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
             may have different types but same value here.  */
          if (!OP_SAME (0))
            return 0;
-         flags &= ~OEP_CONSTANT_ADDRESS_OF;
+         flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF);
          return ((tree_int_cst_equal (TREE_OPERAND (arg0, 1),
                                       TREE_OPERAND (arg1, 1))
                   || OP_SAME (1))
@@ -2975,13 +2984,13 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
          if (!OP_SAME_WITH_NULL (0)
              || !OP_SAME (1))
            return 0;
-         flags &= ~OEP_CONSTANT_ADDRESS_OF;
+         flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF);
          return OP_SAME_WITH_NULL (2);
 
        case BIT_FIELD_REF:
          if (!OP_SAME (0))
            return 0;
-         flags &= ~OEP_CONSTANT_ADDRESS_OF;
+         flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF);
          return OP_SAME (1) && OP_SAME (2);
 
        default:
@@ -2992,6 +3001,10 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
       switch (TREE_CODE (arg0))
        {
        case ADDR_EXPR:
+         return operand_equal_p (TREE_OPERAND (arg0, 0),
+                                 TREE_OPERAND (arg1, 0),
+                                 flags | OEP_ADDRESS_OF);
+
        case TRUTH_NOT_EXPR:
          return OP_SAME (0);
 
index 8a163a1..d956c36 100644 (file)
@@ -812,6 +812,10 @@ proper position among the other output files.  */
     %{fvtable-verify=preinit: -lvtv -u_vtable_map_vars_start -u_vtable_map_vars_end}}"
 #endif
 
+#ifndef CHKP_SPEC
+#define CHKP_SPEC ""
+#endif
+
 /* -u* was put back because both BSD and SysV seem to support it.  */
 /* %{static:} simply prevents an error message if the target machine
    doesn't handle -static.  */
@@ -832,6 +836,7 @@ proper position among the other output files.  */
    "%X %{o*} %{e*} %{N} %{n} %{r}\
     %{s} %{t} %{u*} %{z} %{Z} %{!nostdlib:%{!nostartfiles:%S}} " VTABLE_VERIFICATION_SPEC " \
     %{static:} %{L*} %(mfwrap) %(link_libgcc) " SANITIZER_EARLY_SPEC " %o\
+    " CHKP_SPEC " \
     %{fopenacc|fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)}\
     %{fcilkplus:%:include(libcilkrts.spec)%(link_cilkrts)}\
     %{fgnu-tm:%:include(libitm.spec)%(link_itm)}\
index a1eb24c..5fb0d78 100644 (file)
@@ -292,9 +292,10 @@ print_graph_cfg (const char *base, struct function *fun)
   pretty_printer graph_slim_pp;
   graph_slim_pp.buffer->stream = fp;
   pretty_printer *const pp = &graph_slim_pp;
-  pp_printf (pp, "subgraph \"%s\" {\n"
-                "\tcolor=\"black\";\n"
-                "\tlabel=\"%s\";\n",
+  pp_printf (pp, "subgraph \"cluster_%s\" {\n"
+                "\tstyle=\"dashed\";\n"
+                "\tcolor=\"black\";\n"
+                "\tlabel=\"%s ()\";\n",
                 funcname, funcname);
   draw_cfg_nodes (pp, fun);
   draw_cfg_edges (pp, fun);
index 0b857ff..3bea06a 100644 (file)
@@ -100,6 +100,44 @@ along with GCC; see the file COPYING3.  If not see
     removed.  */
 
 #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
+#define CHKP_WRAPPER_SYMBOL_PREFIX "__mpx_wrapper_"
+
+/* Return 1 calls to FNDECL should be replaced with
+   a call to wrapper function.  */
+static bool
+chkp_wrap_function (tree fndecl)
+{
+  if (!flag_chkp_use_wrappers)
+    return false;
+
+  if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+    {
+      switch (DECL_FUNCTION_CODE (fndecl))
+       {
+       case BUILT_IN_STRLEN:
+       case BUILT_IN_STRCPY:
+       case BUILT_IN_STRNCPY:
+       case BUILT_IN_STPCPY:
+       case BUILT_IN_STPNCPY:
+       case BUILT_IN_STRCAT:
+       case BUILT_IN_STRNCAT:
+       case BUILT_IN_MEMCPY:
+       case BUILT_IN_MEMPCPY:
+       case BUILT_IN_MEMSET:
+       case BUILT_IN_MEMMOVE:
+       case BUILT_IN_BZERO:
+       case BUILT_IN_MALLOC:
+       case BUILT_IN_CALLOC:
+       case BUILT_IN_REALLOC:
+         return 1;
+
+       default:
+         return 0;
+       }
+    }
+
+  return false;
+}
 
 /* Build a clone of FNDECL with a modified name.  */
 
@@ -124,11 +162,20 @@ chkp_build_instrumented_fndecl (tree fndecl)
      because it conflicts with decl merging algorithms in LTO.
      Achieve the result by using transparent alias name for the
      instrumented version.  */
-  s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
-  s += ".chkp";
-  new_name = get_identifier (s.c_str ());
-  IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1;
-  TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl);
+  if (chkp_wrap_function(fndecl))
+    {
+      s = CHKP_WRAPPER_SYMBOL_PREFIX;
+      s += IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
+      new_name = get_identifier (s.c_str ());
+    }
+  else
+    {
+      s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
+      s += ".chkp";
+      new_name = get_identifier (s.c_str ());
+      IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1;
+      TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl);
+    }
   SET_DECL_ASSEMBLER_NAME (new_decl, new_name);
 
   /* For functions with body versioning will make a copy of arguments.
index fe29932..c9d153c 100644 (file)
@@ -61,7 +61,7 @@ along with GCC; see the file COPYING3.  If not see
        In the case of single inheritance, the virtual table is shared
        and BINFO_VTABLE of base BINFO is NULL.  In the case of multiple
        inheritance the individual virtual tables are pointer to by
-       BINFO_VTABLE of base binfos (that differs of BINFO_VTABLE of 
+       BINFO_VTABLE of base binfos (that differs of BINFO_VTABLE of
        binfo associated to the base type).
 
        BINFO lookup for a given base type and offset can be done by
@@ -88,7 +88,7 @@ along with GCC; see the file COPYING3.  If not see
      This means that the graph is not complete. Types with no methods are not
      inserted into the graph.  Also types without virtual methods are not
      represented at all, though it may be easy to add this.
-  
      The inheritance graph is represented as follows:
 
        Vertices are structures odr_type.  Every odr_type may correspond
@@ -213,7 +213,7 @@ static bool odr_violation_reported = false;
 static hash_set<cgraph_node *> *cached_polymorphic_call_targets;
 
 /* The node of type inheritance graph.  For each type unique in
-   One Definition Rule (ODR) sense, we produce one node linking all 
+   One Definition Rule (ODR) sense, we produce one node linking all
    main variants of types equivalent to it, bases and derived types.  */
 
 struct GTY(()) odr_type_d
@@ -272,7 +272,7 @@ type_all_ctors_visible_p (tree t)
         && symtab->state >= CONSTRUCTION
         /* We can not always use type_all_derivations_known_p.
            For function local types we must assume case where
-           the function is COMDAT and shared in between units. 
+           the function is COMDAT and shared in between units.
 
            TODO: These cases are quite easy to get, but we need
            to keep track of C++ privatizing via -Wno-weak
@@ -299,9 +299,10 @@ type_possibly_instantiated_p (tree t)
   return vnode && vnode->definition;
 }
 
-/* One Definition Rule hashtable helpers.  */
+/* Hash used to unify ODR types based on their mangled name and for anonymous
+   namespace types.  */
 
-struct odr_hasher 
+struct odr_name_hasher
 {
   typedef odr_type_d value_type;
   typedef union tree_node compare_type;
@@ -310,6 +311,16 @@ struct odr_hasher
   static inline void remove (value_type *);
 };
 
+/* Has used to unify ODR types based on their associated virtual table.
+   This hash is needed to keep -fno-lto-odr-type-merging to work and contains
+   only polymorphic types.  Types with mangled names are inserted to both.  */
+
+struct odr_vtable_hasher:odr_name_hasher
+{
+  static inline hashval_t hash (const value_type *);
+  static inline bool equal (const value_type *, const compare_type *);
+};
+
 /* Return type that was declared with T's name so that T is an
    qualified variant of it.  */
 
@@ -323,10 +334,17 @@ main_odr_variant (const_tree t)
     return TYPE_MAIN_VARIANT (t);
 }
 
-/* Produce hash based on type name.  */
+static bool
+can_be_name_hashed_p (tree t)
+{
+  return (!in_lto_p || type_in_anonymous_namespace_p (t)
+         || (TYPE_NAME (t) && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t))));
+}
+
+/* Hash type by its ODR name.  */
 
 static hashval_t
-hash_type_name (tree t)
+hash_odr_name (const_tree t)
 {
   gcc_checking_assert (main_odr_variant (t) == t);
 
@@ -339,65 +357,91 @@ hash_type_name (tree t)
   if (type_in_anonymous_namespace_p (t))
     return htab_hash_pointer (t);
 
-  /* ODR types have name specified.  */
-  if (TYPE_NAME (t)
-      && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t)))
-    return IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME (TYPE_NAME (t)));
+  gcc_checking_assert (TYPE_NAME (t)
+                      && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t)));
+  return IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME (TYPE_NAME (t)));
+}
 
-  /* For polymorphic types that was compiled with -fno-lto-odr-type-merging
-     we can simply hash the virtual table.  */
-  if (TREE_CODE (t) == RECORD_TYPE
-      && TYPE_BINFO (t) && BINFO_VTABLE (TYPE_BINFO (t)))
-    {
-      tree v = BINFO_VTABLE (TYPE_BINFO (t));
-      hashval_t hash = 0;
+/* Return the computed hashcode for ODR_TYPE.  */
 
-      if (TREE_CODE (v) == POINTER_PLUS_EXPR)
-       {
-         hash = TREE_INT_CST_LOW (TREE_OPERAND (v, 1));
-         v = TREE_OPERAND (TREE_OPERAND (v, 0), 0);
-       }
+inline hashval_t
+odr_name_hasher::hash (const value_type *odr_type)
+{
+  return hash_odr_name (odr_type->type);
+}
+
+static bool
+can_be_vtable_hashed_p (tree t)
+{
+  /* vtable hashing can distinguish only main variants.  */
+  if (TYPE_MAIN_VARIANT (t) != t)
+    return false;
+  /* Anonymous namespace types are always handled by name hash.  */
+  if (type_in_anonymous_namespace_p (t))
+    return false;
+  return (TREE_CODE (t) == RECORD_TYPE
+         && TYPE_BINFO (t) && BINFO_VTABLE (TYPE_BINFO (t)));
+}
+
+/* Hash type by assembler name of its vtable.  */
+
+static hashval_t
+hash_odr_vtable (const_tree t)
+{
+  tree v = BINFO_VTABLE (TYPE_BINFO (TYPE_MAIN_VARIANT (t)));
+  inchash::hash hstate;
+
+  gcc_checking_assert (in_lto_p);
+  gcc_checking_assert (!type_in_anonymous_namespace_p (t));
+  gcc_checking_assert (TREE_CODE (t) == RECORD_TYPE
+                      && TYPE_BINFO (t) && BINFO_VTABLE (TYPE_BINFO (t)));
+  gcc_checking_assert (main_odr_variant (t) == t);
 
-      v = DECL_ASSEMBLER_NAME (v);
-      hash = iterative_hash_hashval_t (hash, htab_hash_pointer (v));
-      return hash;
+  if (TREE_CODE (v) == POINTER_PLUS_EXPR)
+    {
+      add_expr (TREE_OPERAND (v, 1), hstate);
+      v = TREE_OPERAND (TREE_OPERAND (v, 0), 0);
     }
 
-  /* Builtin types may appear as main variants of ODR types and are unique.
-     Sanity check we do not get anything that looks non-builtin.  */
-  gcc_checking_assert (TREE_CODE (t) == INTEGER_TYPE
-                      || TREE_CODE (t) == VOID_TYPE
-                      || TREE_CODE (t) == COMPLEX_TYPE
-                      || TREE_CODE (t) == REAL_TYPE
-                      || TREE_CODE (t) == POINTER_TYPE);
-  return htab_hash_pointer (t);
+  hstate.add_wide_int (IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME (v)));
+  return hstate.end ();
 }
 
 /* Return the computed hashcode for ODR_TYPE.  */
 
 inline hashval_t
-odr_hasher::hash (const value_type *odr_type)
+odr_vtable_hasher::hash (const value_type *odr_type)
 {
-  return hash_type_name (odr_type->type);
+  return hash_odr_vtable (odr_type->type);
 }
 
 /* For languages with One Definition Rule, work out if
    types are the same based on their name.
+
    This is non-trivial for LTO where minor differences in
    the type representation may have prevented type merging
    to merge two copies of otherwise equivalent type.
 
    Until we start streaming mangled type names, this function works
-   only for polymorphic types.  */
+   only for polymorphic types.
+
+   When STRICT is true, we compare types by their names for purposes of
+   ODR violation warnings.  When strict is false, we consider variants
+   equivalent, becuase it is all that matters for devirtualization machinery.
+*/
 
 bool
-types_same_for_odr (const_tree type1, const_tree type2)
+types_same_for_odr (const_tree type1, const_tree type2, bool strict)
 {
   gcc_checking_assert (TYPE_P (type1) && TYPE_P (type2));
 
   type1 = main_odr_variant (type1);
   type2 = main_odr_variant (type2);
+  if (!strict)
+    {
+      type1 = TYPE_MAIN_VARIANT (type1);
+      type2 = TYPE_MAIN_VARIANT (type2);
+    }
 
   if (type1 == type2)
     return true;
@@ -434,7 +478,8 @@ types_same_for_odr (const_tree type1, const_tree type2)
       if (TREE_CODE (type1) != TREE_CODE (type2))
        return false;
       if (TREE_CODE (type1) == RECORD_TYPE
-         && (TYPE_BINFO (type1) == NULL_TREE) != (TYPE_BINFO (type1) == NULL_TREE))
+         && (TYPE_BINFO (type1) == NULL_TREE)
+             != (TYPE_BINFO (type1) == NULL_TREE))
        return false;
       if (TREE_CODE (type1) == RECORD_TYPE && TYPE_BINFO (type1)
          && (BINFO_VTABLE (TYPE_BINFO (type1)) == NULL_TREE)
@@ -471,13 +516,16 @@ types_same_for_odr (const_tree type1, const_tree type2)
 /* Return true if we can decide on ODR equivalency.
 
    In non-LTO it is always decide, in LTO however it depends in the type has
-   ODR info attached.  */
+   ODR info attached.
+
+   When STRICT is false, compare main variants.  */
 
 bool
-types_odr_comparable (tree t1, tree t2)
+types_odr_comparable (tree t1, tree t2, bool strict)
 {
   return (!in_lto_p
-         || main_odr_variant (t1) == main_odr_variant (t2)
+         || (strict ? main_odr_variant (t1) == main_odr_variant (t2)
+             : TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
          || (odr_type_p (t1) && odr_type_p (t2))
          || (TREE_CODE (t1) == RECORD_TYPE && TREE_CODE (t2) == RECORD_TYPE
              && TYPE_BINFO (t1) && TYPE_BINFO (t2)
@@ -494,29 +542,63 @@ types_must_be_same_for_odr (tree t1, tree t2)
   if (types_odr_comparable (t1, t2))
     return types_same_for_odr (t1, t2);
   else
-    return main_odr_variant (t1) == main_odr_variant (t2);
+    return TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2);
 }
 
 /* Compare types T1 and T2 and return true if they are
    equivalent.  */
 
 inline bool
-odr_hasher::equal (const value_type *t1, const compare_type *ct2)
+odr_name_hasher::equal (const value_type *o1, const compare_type *t2)
 {
-  tree t2 = const_cast <tree> (ct2);
+  tree t1 = o1->type;
 
   gcc_checking_assert (main_odr_variant (t2) == t2);
-  if (t1->type == t2)
+  gcc_checking_assert (main_odr_variant (t1) == t1);
+  if (t1 == t2)
     return true;
   if (!in_lto_p)
     return false;
-  return types_same_for_odr (t1->type, t2);
+  /* Check for anonymous namespaces. Those have !TREE_PUBLIC
+     on the corresponding TYPE_STUB_DECL.  */
+  if (type_in_anonymous_namespace_p (t1)
+      || type_in_anonymous_namespace_p (t2))
+    return false;
+  gcc_checking_assert (DECL_ASSEMBLER_NAME (TYPE_NAME (t1)));
+  gcc_checking_assert (DECL_ASSEMBLER_NAME (TYPE_NAME (t2)));
+  return (DECL_ASSEMBLER_NAME (TYPE_NAME (t1))
+         == DECL_ASSEMBLER_NAME (TYPE_NAME (t2)));
+}
+
+/* Compare types T1 and T2 and return true if they are
+   equivalent.  */
+
+inline bool
+odr_vtable_hasher::equal (const value_type *o1, const compare_type *t2)
+{
+  tree t1 = o1->type;
+
+  gcc_checking_assert (main_odr_variant (t2) == t2);
+  gcc_checking_assert (main_odr_variant (t1) == t1);
+  gcc_checking_assert (in_lto_p);
+  t1 = TYPE_MAIN_VARIANT (t1);
+  t2 = TYPE_MAIN_VARIANT (t2);
+  if (t1 == t2)
+    return true;
+  tree v1 = BINFO_VTABLE (TYPE_BINFO (t1));
+  tree v2 = BINFO_VTABLE (TYPE_BINFO (t2));
+  return (operand_equal_p (TREE_OPERAND (v1, 1),
+                          TREE_OPERAND (v2, 1), 0)
+         && DECL_ASSEMBLER_NAME
+                (TREE_OPERAND (TREE_OPERAND (v1, 0), 0))
+            == DECL_ASSEMBLER_NAME
+                (TREE_OPERAND (TREE_OPERAND (v2, 0), 0)));
 }
 
 /* Free ODR type V.  */
 
 inline void
-odr_hasher::remove (value_type *v)
+odr_name_hasher::remove (value_type *v)
 {
   v->bases.release ();
   v->derived_types.release ();
@@ -527,8 +609,10 @@ odr_hasher::remove (value_type *v)
 
 /* ODR type hash used to look up ODR type based on tree type node.  */
 
-typedef hash_table<odr_hasher> odr_hash_type;
+typedef hash_table<odr_name_hasher> odr_hash_type;
 static odr_hash_type *odr_hash;
+typedef hash_table<odr_vtable_hasher> odr_vtable_hash_type;
+static odr_vtable_hash_type *odr_vtable_hash;
 
 /* ODR types are also stored into ODR_TYPE vector to allow consistent
    walking.  Bases appear before derived types.  Vector is garbage collected
@@ -573,9 +657,9 @@ odr_subtypes_equivalent_p (tree t1, tree t2,
   /* For ODR types be sure to compare their names.
      To support -wno-odr-type-merging we allow one type to be non-ODR
      and other ODR even though it is a violation.  */
-  if (types_odr_comparable (t1, t2))
+  if (types_odr_comparable (t1, t2, true))
     {
-      if (!types_same_for_odr (t1, t2))
+      if (!types_same_for_odr (t1, t2, true))
         return false;
       /* Limit recursion: If subtypes are ODR types and we know
          that they are same, be happy.  */
@@ -681,7 +765,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
        {
          /* Extra paranoia; compare the sizes.  We do not have information
             about virtual inheritance offsets, so just be sure that these
-            match.  
+            match. 
             Do this as very last check so the not very informative error
             is not output too often.  */
          if (DECL_SIZE (prevailing->decl) != DECL_SIZE (vtable->decl))
@@ -692,7 +776,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
                              "one definition rule  ",
                              DECL_CONTEXT (vtable->decl)))
                {
-                 inform (DECL_SOURCE_LOCATION 
+                 inform (DECL_SOURCE_LOCATION
                            (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
                          "the conflicting type defined in another translation "
                          "unit has virtual table of different size");
@@ -718,10 +802,10 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
                              "one definition rule  ",
                              DECL_CONTEXT (vtable->decl)))
                {
-                 inform (DECL_SOURCE_LOCATION 
+                 inform (DECL_SOURCE_LOCATION
                            (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
                          "the conflicting type defined in another translation "
-                         "unit virtual table with different RTTI information");
+                         "unit with different RTTI information");
                }
              return;
            }
@@ -794,7 +878,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
        {
          if (TREE_CODE (ref1->referred->decl) == FUNCTION_DECL)
            {
-             inform (DECL_SOURCE_LOCATION 
+             inform (DECL_SOURCE_LOCATION
                        (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
                      "the conflicting type defined in another translation "
                      "unit");
@@ -807,7 +891,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
                      ref2->referred->decl);
            }
          else
-           inform (DECL_SOURCE_LOCATION 
+           inform (DECL_SOURCE_LOCATION
                      (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
                    "the conflicting type defined in another translation "
                    "unit has virtual table table with different contents");
@@ -1312,32 +1396,45 @@ odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned,
 
 /* TYPE is equivalent to VAL by ODR, but its tree representation differs
    from VAL->type.  This may happen in LTO where tree merging did not merge
-   all variants of the same type.  It may or may not mean the ODR violation.
-   Add it to the list of duplicates and warn on some violations.  */
+   all variants of the same type or due to ODR violation.
+
+   Analyze and report ODR violations and add type to duplicate list.
+   If TYPE is more specified than VAL->type, prevail VAL->type.  Also if
+   this is first time we see definition of a class return true so the
+   base types are analyzed.  */
 
 static bool
 add_type_duplicate (odr_type val, tree type)
 {
   bool build_bases = false;
+  bool prevail = false;
+
   if (!val->types_set)
     val->types_set = new hash_set<tree>;
 
   /* Always prefer complete type to be the leader.  */
 
   if (!COMPLETE_TYPE_P (val->type) && COMPLETE_TYPE_P (type))
-    build_bases = true;
+    {
+      prevail = true;
+      build_bases = TYPE_BINFO (type);
+    }
   else if (COMPLETE_TYPE_P (val->type) && !COMPLETE_TYPE_P (type))
     ;
   else if (TREE_CODE (val->type) == ENUMERAL_TYPE
           && TREE_CODE (type) == ENUMERAL_TYPE
           && !TYPE_VALUES (val->type) && TYPE_VALUES (type))
-    build_bases = true;
+    prevail = true;
   else if (TREE_CODE (val->type) == RECORD_TYPE
           && TREE_CODE (type) == RECORD_TYPE
           && TYPE_BINFO (type) && !TYPE_BINFO (val->type))
-    build_bases = true;
+    {
+      gcc_assert (!val->bases.length ());
+      build_bases = true;
+      prevail = true;
+    }
 
-  if (build_bases)
+  if (prevail)
     {
       tree tmp = type;
 
@@ -1345,29 +1442,178 @@ add_type_duplicate (odr_type val, tree type)
       val->type = tmp;
     }
 
-  /* See if this duplicate is new.  */
-  if (!val->types_set->add (type))
+  val->types_set->add (type);
+
+  /* If we now have a mangled name, be sure to record it to val->type
+     so ODR hash can work.  */
+
+  if (can_be_name_hashed_p (type) && !can_be_name_hashed_p (val->type))
+    SET_DECL_ASSEMBLER_NAME (TYPE_NAME (val->type),
+                            DECL_ASSEMBLER_NAME (TYPE_NAME (type)));
+
+  bool merge = true;
+  bool base_mismatch = false;
+  unsigned int i;
+  bool warned = false;
+  hash_set<type_pair,pair_traits> visited;
+
+  gcc_assert (in_lto_p);
+  vec_safe_push (val->types, type);
+
+  /* First we compare memory layout.  */
+  if (!odr_types_equivalent_p (val->type, type,
+                              !flag_ltrans && !val->odr_violated,
+                              &warned, &visited))
     {
-      bool merge = true;
-      bool base_mismatch = false;
-      unsigned int i;
-      bool warned = false;
-      hash_set<type_pair,pair_traits> visited;
+      merge = false;
+      odr_violation_reported = true;
+      val->odr_violated = true;
+      if (symtab->dump_file)
+       {
+         fprintf (symtab->dump_file, "ODR violation\n");
+
+         print_node (symtab->dump_file, "", val->type, 0);
+         putc ('\n',symtab->dump_file);
+         print_node (symtab->dump_file, "", type, 0);
+         putc ('\n',symtab->dump_file);
+       }
+    }
+
+  /* Next sanity check that bases are the same.  If not, we will end
+     up producing wrong answers.  */
+  if (COMPLETE_TYPE_P (type) && COMPLETE_TYPE_P (val->type)
+      && TREE_CODE (val->type) == RECORD_TYPE
+      && TREE_CODE (type) == RECORD_TYPE
+      && TYPE_BINFO (val->type) && TYPE_BINFO (type))
+    {
+      if (BINFO_N_BASE_BINFOS (TYPE_BINFO (type))
+         != BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type)))
+       {
+         if (!warned && !val->odr_violated)
+           {
+             tree extra_base;
+             warn_odr (type, val->type, NULL, NULL, !warned, &warned,
+                       "a type with the same name but different "
+                       "number of polymorphic bases is "
+                       "defined in another translation unit");
+             if (BINFO_N_BASE_BINFOS (TYPE_BINFO (type))
+                 > BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type)))
+               extra_base = BINFO_BASE_BINFO
+                            (TYPE_BINFO (type),
+                             BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type)));
+             else
+               extra_base = BINFO_BASE_BINFO
+                            (TYPE_BINFO (val->type),
+                             BINFO_N_BASE_BINFOS (TYPE_BINFO (type)));
+             tree extra_base_type = BINFO_TYPE (extra_base);
+             inform (DECL_SOURCE_LOCATION (TYPE_NAME (extra_base_type)),
+                     "the extra base is defined here");
+           }
+         base_mismatch = true;
+       }
+      else
+       for (i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type)); i++)
+         {
+           tree base1 = BINFO_BASE_BINFO (TYPE_BINFO (type), i);
+           tree base2 = BINFO_BASE_BINFO (TYPE_BINFO (val->type), i);
+           tree type1 = BINFO_TYPE (base1);
+           tree type2 = BINFO_TYPE (base2);
 
-      gcc_assert (in_lto_p);
-      vec_safe_push (val->types, type);
+           if (types_odr_comparable (type1, type2))
+             {
+               if (!types_same_for_odr (type1, type2))
+                 base_mismatch = true;
+             }
+           else
+             {
+               hash_set<type_pair,pair_traits> visited;
+               if (!odr_types_equivalent_p (type1, type2, false, NULL,
+                                            &visited))
+                 base_mismatch = true;
+             }
+           if (base_mismatch)
+             {
+               if (!warned && !val->odr_violated)
+                 {
+                   warn_odr (type, val->type, NULL, NULL,
+                             !warned, &warned,
+                             "a type with the same name but different base "
+                             "type is defined in another translation unit");
+                   if (warned)
+                     warn_types_mismatch (type1, type2);
+                 }
+               break;
+             }
+           if (BINFO_OFFSET (base1) != BINFO_OFFSET (base2))
+             {
+               base_mismatch = true;
+               if (!warned && !val->odr_violated)
+                 warn_odr (type, val->type, NULL, NULL,
+                           !warned, &warned,
+                           "a type with the same name but different base "
+                           "layout is defined in another translation unit");
+               break;
+             }
+           /* One of bases is not of complete type.  */
+           if (!TYPE_BINFO (type1) != !TYPE_BINFO (type2))
+             {
+               /* If we have a polymorphic type info specified for TYPE1
+                  but not for TYPE2 we possibly missed a base when recording
+                  VAL->type earlier.
+                  Be sure this does not happen.  */
+               gcc_assert (TYPE_BINFO (type2)
+                           || !polymorphic_type_binfo_p (TYPE_BINFO (type1))
+                           || build_bases);
+               break;
+             }
+           /* One base is polymorphic and the other not.
+              This ought to be diagnosed earlier, but do not ICE in the
+              checking bellow.  */
+           else if (TYPE_BINFO (type1)
+                    && polymorphic_type_binfo_p (TYPE_BINFO (type1))
+                       != polymorphic_type_binfo_p (TYPE_BINFO (type2)))
+             {
+               gcc_assert (val->odr_violated);
+               base_mismatch = true;
+               break;
+             }
+         }
+#ifdef ENABLE_CHECKING
+      /* Sanity check that all bases will be build same way again.  */
+      if (!base_mismatch && val->bases.length ())
+       {
+         unsigned int num_poly_bases = 0;
+         unsigned int j;
 
-      /* First we compare memory layout.  */
-      if (!odr_types_equivalent_p (val->type, type,
-                                  !flag_ltrans && !val->odr_violated,
-                                  &warned, &visited))
+         for (i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type)); i++)
+           if (polymorphic_type_binfo_p (BINFO_BASE_BINFO
+                                            (TYPE_BINFO (type), i)))
+             num_poly_bases++;
+         gcc_assert (num_poly_bases == val->bases.length ());
+         for (j = 0, i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type));
+              i++)
+           if (polymorphic_type_binfo_p (BINFO_BASE_BINFO
+                                          (TYPE_BINFO (type), i)))
+             {
+               odr_type base = get_odr_type
+                                  (BINFO_TYPE
+                                     (BINFO_BASE_BINFO (TYPE_BINFO (type),
+                                                        i)),
+                                   true);
+               gcc_assert (val->bases[j] == base);
+               j++;
+             }
+       }
+#endif
+      if (base_mismatch)
        {
          merge = false;
          odr_violation_reported = true;
          val->odr_violated = true;
+
          if (symtab->dump_file)
            {
-             fprintf (symtab->dump_file, "ODR violation\n");
+             fprintf (symtab->dump_file, "ODR base violation\n");
            
              print_node (symtab->dump_file, "", val->type, 0);
              putc ('\n',symtab->dump_file);
@@ -1375,197 +1621,65 @@ add_type_duplicate (odr_type val, tree type)
              putc ('\n',symtab->dump_file);
            }
        }
+    }
 
-      /* Next sanity check that bases are the same.  If not, we will end
-        up producing wrong answers.  */
-      if (COMPLETE_TYPE_P (type) && COMPLETE_TYPE_P (val->type)
-         && TREE_CODE (val->type) == RECORD_TYPE
-         && TREE_CODE (type) == RECORD_TYPE
-         && TYPE_BINFO (val->type) && TYPE_BINFO (type))
-       {
-         if (BINFO_N_BASE_BINFOS (TYPE_BINFO (type))
-             != BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type)))
-           {
-             if (!warned && !val->odr_violated)
-               {
-                 tree extra_base;
-                 warn_odr (type, val->type, NULL, NULL, !warned, &warned,
-                           "a type with the same name but different "
-                           "number of polymorphic bases is "
-                           "defined in another translation unit");
-                 if (BINFO_N_BASE_BINFOS (TYPE_BINFO (type))
-                     > BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type)))
-                   extra_base = BINFO_BASE_BINFO
-                                (TYPE_BINFO (type),
-                                 BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type)));
-                 else
-                   extra_base = BINFO_BASE_BINFO
-                                (TYPE_BINFO (val->type),
-                                 BINFO_N_BASE_BINFOS (TYPE_BINFO (type)));
-                 inform (DECL_SOURCE_LOCATION 
-                           (TYPE_NAME (DECL_CONTEXT (extra_base))),
-                         "the extra base is defined here ");
-               }
-             base_mismatch = true;
-           }
-         else
-           for (i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type)); i++)
-             {
-               tree base1 = BINFO_BASE_BINFO (TYPE_BINFO (type), i);
-               tree base2 = BINFO_BASE_BINFO (TYPE_BINFO (val->type), i);
-               tree type1 = BINFO_TYPE (base1);
-               tree type2 = BINFO_TYPE (base2);
-
-               if (types_odr_comparable (type1, type2))
-                 {
-                   if (!types_same_for_odr (type1, type2))
-                     base_mismatch = true;
-                 }
-               else
-                 {
-                   hash_set<type_pair,pair_traits> visited;
-                   if (!odr_types_equivalent_p (type1, type2, false, NULL,
-                                                &visited))
-                     base_mismatch = true;
-                 }
-               if (base_mismatch)
-                 {
-                   if (!warned && !val->odr_violated)
-                     {
-                       warn_odr (type, val->type, NULL, NULL,
-                                 !warned, &warned,
-                                 "a type with the same name but different base "
-                                 "type is defined in another translation unit");
-                       if (warned)
-                         warn_types_mismatch (type1, type2);
-                     }
-                   break;
-                 }
-               if (BINFO_OFFSET (base1) != BINFO_OFFSET (base2))
-                 {
-                   base_mismatch = true;
-                   if (!warned && !val->odr_violated)
-                     warn_odr (type, val->type, NULL, NULL,
-                               !warned, &warned,
-                               "a type with the same name but different base "
-                               "layout is defined in another translation unit");
-                   break;
-                 }
-               /* One base is polymorphic and the other not.
-                  This ought to be diagnosed earlier, but do not ICE in the
-                  checking bellow.  */
-               if (!TYPE_BINFO (type1) != !TYPE_BINFO (type2)
-                   || (TYPE_BINFO (type1)
-                       && polymorphic_type_binfo_p (TYPE_BINFO (type1))
-                          != polymorphic_type_binfo_p (TYPE_BINFO (type2))))
-                 {
-                   base_mismatch = true;
-                   break;
-                 }
-             }
-#ifdef ENABLE_CHECKING
-         /* Sanity check that all bases will be build same way again.  */
-         if (!base_mismatch && val->bases.length ())
-           {
-             unsigned int num_poly_bases = 0;
-             unsigned int j;
-
-             for (i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type)); i++)
-               if (polymorphic_type_binfo_p (BINFO_BASE_BINFO
-                                                (TYPE_BINFO (type), i)))
-                 num_poly_bases++;
-             gcc_assert (num_poly_bases == val->bases.length ());
-             for (j = 0, i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type));
-                  i++)
-               if (polymorphic_type_binfo_p (BINFO_BASE_BINFO 
-                                              (TYPE_BINFO (type), i)))
-                 {
-                   odr_type base = get_odr_type
-                                      (BINFO_TYPE
-                                         (BINFO_BASE_BINFO (TYPE_BINFO (type),
-                                                            i)),
-                                       true);
-                   gcc_assert (val->bases[j] == base);
-                   j++;
-                 }
-           }
-#endif
-         if (base_mismatch)
-           {
-             merge = false;
-             odr_violation_reported = true;
-             val->odr_violated = true;
+  /* Regularize things a little.  During LTO same types may come with
+     different BINFOs.  Either because their virtual table was
+     not merged by tree merging and only later at decl merging or
+     because one type comes with external vtable, while other
+     with internal.  We want to merge equivalent binfos to conserve
+     memory and streaming overhead.
+
+     The external vtables are more harmful: they contain references
+     to external declarations of methods that may be defined in the
+     merged LTO unit.  For this reason we absolutely need to remove
+     them and replace by internal variants. Not doing so will lead
+     to incomplete answers from possible_polymorphic_call_targets.
+
+     FIXME: disable for now; because ODR types are now build during
+     streaming in, the variants do not need to be linked to the type,
+     yet.  We need to do the merging in cleanup pass to be implemented
+     soon.  */
+  if (!flag_ltrans && merge
+      && 0
+      && TREE_CODE (val->type) == RECORD_TYPE
+      && TREE_CODE (type) == RECORD_TYPE
+      && TYPE_BINFO (val->type) && TYPE_BINFO (type)
+      && TYPE_MAIN_VARIANT (type) == type
+      && TYPE_MAIN_VARIANT (val->type) == val->type
+      && BINFO_VTABLE (TYPE_BINFO (val->type))
+      && BINFO_VTABLE (TYPE_BINFO (type)))
+    {
+      tree master_binfo = TYPE_BINFO (val->type);
+      tree v1 = BINFO_VTABLE (master_binfo);
+      tree v2 = BINFO_VTABLE (TYPE_BINFO (type));
 
-             if (symtab->dump_file)
-               {
-                 fprintf (symtab->dump_file, "ODR base violation\n");
-               
-                 print_node (symtab->dump_file, "", val->type, 0);
-                 putc ('\n',symtab->dump_file);
-                 print_node (symtab->dump_file, "", type, 0);
-                 putc ('\n',symtab->dump_file);
-               }
-           }
+      if (TREE_CODE (v1) == POINTER_PLUS_EXPR)
+       {
+         gcc_assert (TREE_CODE (v2) == POINTER_PLUS_EXPR
+                     && operand_equal_p (TREE_OPERAND (v1, 1),
+                                         TREE_OPERAND (v2, 1), 0));
+         v1 = TREE_OPERAND (TREE_OPERAND (v1, 0), 0);
+         v2 = TREE_OPERAND (TREE_OPERAND (v2, 0), 0);
        }
+      gcc_assert (DECL_ASSEMBLER_NAME (v1)
+                 == DECL_ASSEMBLER_NAME (v2));
 
-      /* Regularize things a little.  During LTO same types may come with
-        different BINFOs.  Either because their virtual table was
-        not merged by tree merging and only later at decl merging or
-        because one type comes with external vtable, while other
-        with internal.  We want to merge equivalent binfos to conserve
-        memory and streaming overhead.
-
-        The external vtables are more harmful: they contain references
-        to external declarations of methods that may be defined in the
-        merged LTO unit.  For this reason we absolutely need to remove
-        them and replace by internal variants. Not doing so will lead
-         to incomplete answers from possible_polymorphic_call_targets.
-
-        FIXME: disable for now; because ODR types are now build during
-        streaming in, the variants do not need to be linked to the type,
-        yet.  We need to do the merging in cleanup pass to be implemented
-        soon.  */
-      if (!flag_ltrans && merge
-         && 0
-         && TREE_CODE (val->type) == RECORD_TYPE
-         && TREE_CODE (type) == RECORD_TYPE
-         && TYPE_BINFO (val->type) && TYPE_BINFO (type)
-         && TYPE_MAIN_VARIANT (type) == type
-         && TYPE_MAIN_VARIANT (val->type) == val->type
-         && BINFO_VTABLE (TYPE_BINFO (val->type))
-         && BINFO_VTABLE (TYPE_BINFO (type)))
+      if (DECL_EXTERNAL (v1) && !DECL_EXTERNAL (v2))
        {
-         tree master_binfo = TYPE_BINFO (val->type);
-         tree v1 = BINFO_VTABLE (master_binfo);
-         tree v2 = BINFO_VTABLE (TYPE_BINFO (type));
+         unsigned int i;
 
-         if (TREE_CODE (v1) == POINTER_PLUS_EXPR)
+         set_type_binfo (val->type, TYPE_BINFO (type));
+         for (i = 0; i < val->types->length (); i++)
            {
-             gcc_assert (TREE_CODE (v2) == POINTER_PLUS_EXPR
-                         && operand_equal_p (TREE_OPERAND (v1, 1),
-                                             TREE_OPERAND (v2, 1), 0));
-             v1 = TREE_OPERAND (TREE_OPERAND (v1, 0), 0);
-             v2 = TREE_OPERAND (TREE_OPERAND (v2, 0), 0);
+             if (TYPE_BINFO ((*val->types)[i])
+                 == master_binfo)
+               set_type_binfo ((*val->types)[i], TYPE_BINFO (type));
            }
-         gcc_assert (DECL_ASSEMBLER_NAME (v1)
-                     == DECL_ASSEMBLER_NAME (v2));
-
-         if (DECL_EXTERNAL (v1) && !DECL_EXTERNAL (v2))
-           {
-             unsigned int i;
-
-             set_type_binfo (val->type, TYPE_BINFO (type));
-             for (i = 0; i < val->types->length (); i++)
-               {
-                 if (TYPE_BINFO ((*val->types)[i])
-                     == master_binfo)
-                   set_type_binfo ((*val->types)[i], TYPE_BINFO (type));
-               }
-             BINFO_TYPE (TYPE_BINFO (type)) = val->type;
-           }
-         else
-           set_type_binfo (type, master_binfo);
+         BINFO_TYPE (TYPE_BINFO (type)) = val->type;
        }
+      else
+       set_type_binfo (type, master_binfo);
     }
   return build_bases;
 }
@@ -1576,8 +1690,9 @@ add_type_duplicate (odr_type val, tree type)
 odr_type
 get_odr_type (tree type, bool insert)
 {
-  odr_type_d **slot;
-  odr_type val;
+  odr_type_d **slot = NULL;
+  odr_type_d **vtable_slot = NULL;
+  odr_type val = NULL;
   hashval_t hash;
   bool build_bases = false;
   bool insert_to_odr_array = false;
@@ -1585,21 +1700,68 @@ get_odr_type (tree type, bool insert)
 
   type = main_odr_variant (type);
 
-  hash = hash_type_name (type);
-  slot = odr_hash->find_slot_with_hash (type, hash,
-                                       insert ? INSERT : NO_INSERT);
-  if (!slot)
+  gcc_checking_assert (can_be_name_hashed_p (type)
+                      || can_be_vtable_hashed_p (type));
+
+  /* Lookup entry, first try name hash, fallback to vtable hash.  */
+  if (can_be_name_hashed_p (type))
+    {
+      hash = hash_odr_name (type);
+      slot = odr_hash->find_slot_with_hash (type, hash,
+                                           insert ? INSERT : NO_INSERT);
+    }
+  if ((!slot || !*slot) && in_lto_p && can_be_vtable_hashed_p (type))
+    {
+      hash = hash_odr_vtable (type);
+      vtable_slot = odr_vtable_hash->find_slot_with_hash (type, hash,
+                                                  insert ? INSERT : NO_INSERT);
+    }
+
+  if (!slot && !vtable_slot)
     return NULL;
 
   /* See if we already have entry for type.  */
-  if (*slot)
+  if ((slot && *slot) || (vtable_slot && *vtable_slot))
     {
-      val = *slot;
+      if (slot && *slot)
+       {
+         val = *slot;
+#ifdef ENABLE_CHECKING
+         if (in_lto_p && can_be_vtable_hashed_p (type))
+           {
+             hash = hash_odr_vtable (type);
+             vtable_slot = odr_vtable_hash->find_slot_with_hash (type, hash,
+                                                                 NO_INSERT);
+             gcc_assert (!vtable_slot || *vtable_slot == *slot);
+             vtable_slot = NULL;
+           }
+#endif
+       }
+      else if (*vtable_slot)
+       val = *vtable_slot;
 
-      /* With LTO we need to support multiple tree representation of
-        the same ODR type.  */
-      if (val->type != type)
-        build_bases = add_type_duplicate (val, type);
+      if (val->type != type
+         && (!val->types_set || !val->types_set->add (type)))
+       {
+         gcc_assert (insert);
+         /* We have type duplicate, but it may introduce vtable name or
+            mangled name; be sure to keep hashes in sync.  */
+         if (in_lto_p && can_be_vtable_hashed_p (type)
+             && (!vtable_slot || !*vtable_slot))
+           {
+             if (!vtable_slot)
+               {
+                 hash = hash_odr_vtable (type);
+                 vtable_slot = odr_vtable_hash->find_slot_with_hash
+                            (type, hash, INSERT);
+                 gcc_checking_assert (!*vtable_slot || *vtable_slot == val);
+               }
+             *vtable_slot = val;
+           }
+         if (slot && !*slot)
+           *slot = val;
+         build_bases = add_type_duplicate (val, type);
+       }
     }
   else
     {
@@ -1610,7 +1772,10 @@ get_odr_type (tree type, bool insert)
       val->anonymous_namespace = type_in_anonymous_namespace_p (type);
       build_bases = COMPLETE_TYPE_P (val->type);
       insert_to_odr_array = true;
-      *slot = val;
+      if (slot)
+        *slot = val;
+      if (vtable_slot)
+       *vtable_slot = val;
     }
 
   if (build_bases && TREE_CODE (type) == RECORD_TYPE && TYPE_BINFO (type)
@@ -1664,7 +1829,11 @@ void
 register_odr_type (tree type)
 {
   if (!odr_hash)
-    odr_hash = new odr_hash_type (23);
+    {
+      odr_hash = new odr_hash_type (23);
+      if (in_lto_p)
+        odr_vtable_hash = new odr_vtable_hash_type (23);
+    }
   /* Arrange things to be nicer and insert main variants first.  */
   if (odr_type_p (TYPE_MAIN_VARIANT (type)))
     get_odr_type (TYPE_MAIN_VARIANT (type), true);
@@ -1784,6 +1953,8 @@ build_type_inheritance_graph (void)
   timevar_push (TV_IPA_INHERITANCE);
   inheritance_dump_file = dump_begin (TDI_inheritance, &flags);
   odr_hash = new odr_hash_type (23);
+  if (in_lto_p)
+    odr_vtable_hash = new odr_vtable_hash_type (23);
 
   /* We reconstruct the graph starting of types of all methods seen in the
      the unit.  */
@@ -2839,12 +3010,12 @@ dump_possible_polymorphic_call_targets (FILE *f,
   targets = possible_polymorphic_call_targets (otr_type, otr_token,
                                               ctx,
                                               &final, NULL, true);
-  gcc_assert (targets.length () <= len);
   if (targets.length () != len)
     {
       fprintf (f, "  Speculative targets:");
       dump_targets (f, targets);
     }
+  gcc_assert (targets.length () <= len);
   fprintf (f, "\n");
 }
 
@@ -3044,6 +3215,9 @@ ipa_devirt (void)
   if (!odr_types_ptr)
     return 0;
 
+  if (dump_file)
+    dump_type_inheritance_graph (dump_file);
+
   /* We can output -Wsuggest-final-methods and -Wsuggest-final-types warnings.
      This is implemented by setting up final_warning_records that are updated
      by get_polymorphic_call_targets.
index 4f1a8ce..568407d 100644 (file)
@@ -200,8 +200,22 @@ func_checker::compare_decl (tree t1, tree t2)
       && DECL_BY_REFERENCE (t1) != DECL_BY_REFERENCE (t2))
     return return_false_with_msg ("DECL_BY_REFERENCE flags are different");
 
-  if (!compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2),
-                          m_compare_polymorphic))
+  if (!compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+    return return_false ();
+
+  /* TODO: we are actually too strict here.  We only need to compare if
+     T1 can be used in polymorphic call.  */
+  if (TREE_ADDRESSABLE (t1)
+      && m_compare_polymorphic
+      && !compatible_polymorphic_types_p (TREE_TYPE (t1), TREE_TYPE (t2),
+                                         false))
+    return return_false ();
+
+  if ((t == VAR_DECL || t == PARM_DECL || t == RESULT_DECL)
+      && DECL_BY_REFERENCE (t1)
+      && m_compare_polymorphic
+      && !compatible_polymorphic_types_p (TREE_TYPE (t1), TREE_TYPE (t2),
+                                         true))
     return return_false ();
 
   bool existed_p;
@@ -215,11 +229,41 @@ func_checker::compare_decl (tree t1, tree t2)
   return true;
 }
 
+/* Return true if T1 and T2 are same for purposes of ipa-polymorphic-call
+   analysis.  COMPARE_PTR indicates if types of pointers needs to be
+   considered.  */
+
+bool
+func_checker::compatible_polymorphic_types_p (tree t1, tree t2,
+                                             bool compare_ptr)
+{
+  gcc_assert (TREE_CODE (t1) != FUNCTION_TYPE && TREE_CODE (t1) != METHOD_TYPE);
+
+  /* Pointer types generally give no information.  */
+  if (POINTER_TYPE_P (t1))
+    {
+      if (!compare_ptr)
+       return true;
+      return func_checker::compatible_polymorphic_types_p (TREE_TYPE (t1),
+                                                          TREE_TYPE (t2),
+                                                          false);
+    }
+
+  /* If types contain a polymorphic types, match them.  */
+  bool c1 = contains_polymorphic_type_p (t1);
+  bool c2 = contains_polymorphic_type_p (t2);
+  if (!c1 && !c2)
+    return true;
+  if (!c1 || !c2)
+    return return_false_with_msg ("one type is not polymorphic");
+  if (!types_must_be_same_for_odr (t1, t2))
+    return return_false_with_msg ("types are not same for ODR");
+  return true;
+}
+
 /* Return true if types are compatible from perspective of ICF.  */
 bool
-func_checker::compatible_types_p (tree t1, tree t2,
-                                 bool compare_polymorphic,
-                                 bool first_argument)
+func_checker::compatible_types_p (tree t1, tree t2)
 {
   if (TREE_CODE (t1) != TREE_CODE (t2))
     return return_false_with_msg ("different tree types");
@@ -233,23 +277,6 @@ func_checker::compatible_types_p (tree t1, tree t2,
   if (get_alias_set (t1) != get_alias_set (t2))
     return return_false_with_msg ("alias sets are different");
 
-  /* We call contains_polymorphic_type_p with this pointer type.  */
-  if (first_argument && TREE_CODE (t1) == POINTER_TYPE)
-    {
-      t1 = TREE_TYPE (t1);
-      t2 = TREE_TYPE (t2);
-    }
-
-  if (compare_polymorphic)
-    if (contains_polymorphic_type_p (t1) || contains_polymorphic_type_p (t2))
-      {
-       if (!contains_polymorphic_type_p (t1) || !contains_polymorphic_type_p (t2))
-         return return_false_with_msg ("one type is not polymorphic");
-
-       if (!types_must_be_same_for_odr (t1, t2))
-         return return_false_with_msg ("types are not same for ODR");
-      }
-
   return true;
 }
 
index a52f8c3..53a1bfe 100644 (file)
@@ -226,12 +226,16 @@ public:
   /* Verifies that trees T1 and T2 do correspond.  */
   bool compare_variable_decl (tree t1, tree t2);
 
+  /* Return true if types are compatible for polymorphic call analysis.
+     COMPARE_PTR indicates if polymorphic type comparsion should be
+     done for pointers, too.  */
+  static bool compatible_polymorphic_types_p (tree t1, tree t2,
+                                             bool compare_ptr);
+
   /* Return true if types are compatible from perspective of ICF.
      FIRST_ARGUMENT indicates if the comparison is called for
      first parameter of a function.  */
-  static bool compatible_types_p (tree t1, tree t2,
-                                 bool compare_polymorphic = true,
-                                 bool first_argument = false);
+  static bool compatible_types_p (tree t1, tree t2);
 
 
 private:
index 7c4c852..25b8306 100644 (file)
@@ -406,6 +406,86 @@ sem_function::equals_wpa (sem_item *item,
   if (arg_types.length () != m_compared_func->arg_types.length ())
     return return_false_with_msg ("different number of arguments");
 
+  /* Compare special function DECL attributes.  */
+  if (DECL_FUNCTION_PERSONALITY (decl)
+      != DECL_FUNCTION_PERSONALITY (item->decl))
+    return return_false_with_msg ("function personalities are different");
+
+  if (DECL_DISREGARD_INLINE_LIMITS (decl)
+      != DECL_DISREGARD_INLINE_LIMITS (item->decl))
+    return return_false_with_msg ("DECL_DISREGARD_INLINE_LIMITS are different");
+
+  if (DECL_DECLARED_INLINE_P (decl) != DECL_DECLARED_INLINE_P (item->decl))
+    return return_false_with_msg ("inline attributes are different");
+
+  if (DECL_IS_OPERATOR_NEW (decl) != DECL_IS_OPERATOR_NEW (item->decl))
+    return return_false_with_msg ("operator new flags are different");
+
+  if (DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl)
+       != DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (item->decl))
+    return return_false_with_msg ("intrument function entry exit "
+                                 "attributes are different");
+
+  if (DECL_NO_LIMIT_STACK (decl) != DECL_NO_LIMIT_STACK (item->decl))
+    return return_false_with_msg ("no stack limit attributes are different");
+
+  if (DECL_CXX_CONSTRUCTOR_P (decl) != DECL_CXX_CONSTRUCTOR_P (item->decl))
+    return return_false_with_msg ("DELC_CXX_CONSTRUCTOR mismatch");
+
+  if (DECL_CXX_DESTRUCTOR_P (decl) != DECL_CXX_DESTRUCTOR_P (item->decl))
+    return return_false_with_msg ("DELC_CXX_DESTRUCTOR mismatch");
+
+  if (flags_from_decl_or_type (decl) != flags_from_decl_or_type (item->decl))
+    return return_false_with_msg ("decl_or_type flags are different");
+
+  /* Do not match polymorphic constructors of different types.  They calls
+     type memory location for ipa-polymorphic-call and we do not want
+     it to get confused by wrong type.  */
+  if (DECL_CXX_CONSTRUCTOR_P (decl)
+      && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
+    {
+      if (TREE_CODE (TREE_TYPE (item->decl)) != METHOD_TYPE)
+        return return_false_with_msg ("DECL_CXX_CONSTURCTOR type mismatch");
+      else if (!func_checker::compatible_polymorphic_types_p
+                (method_class_type (TREE_TYPE (decl)),
+                 method_class_type (TREE_TYPE (item->decl)), false))
+        return return_false_with_msg ("ctor polymorphic type mismatch");
+    }
+
+  /* Checking function TARGET and OPTIMIZATION flags.  */
+  cl_target_option *tar1 = target_opts_for_fn (decl);
+  cl_target_option *tar2 = target_opts_for_fn (item->decl);
+
+  if (tar1 != tar2 && !cl_target_option_eq (tar1, tar2))
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "target flags difference");
+         cl_target_option_print_diff (dump_file, 2, tar1, tar2);
+       }
+
+      return return_false_with_msg ("Target flags are different");
+    }
+
+  cl_optimization *opt1 = opts_for_fn (decl);
+  cl_optimization *opt2 = opts_for_fn (item->decl);
+
+  if (opt1 != opt2 && memcmp (opt1, opt2, sizeof(cl_optimization)))
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "optimization flags difference");
+         cl_optimization_print_diff (dump_file, 2, opt1, opt2);
+       }
+
+      return return_false_with_msg ("optimization flags are different");
+    }
+
+  /* Result type checking.  */
+  if (!func_checker::compatible_types_p (result_type,
+                                        m_compared_func->result_type))
+    return return_false_with_msg ("result types are different");
+
   /* Checking types of arguments.  */
   for (unsigned i = 0; i < arg_types.length (); i++)
     {
@@ -413,13 +493,8 @@ sem_function::equals_wpa (sem_item *item,
       if (!arg_types[i] || !m_compared_func->arg_types[i])
        return return_false_with_msg ("NULL argument type");
 
-      /* Polymorphic comparison is executed just for non-leaf functions.  */
-      bool is_not_leaf = get_node ()->callees != NULL
-                        || get_node ()->indirect_calls != NULL;
-
       if (!func_checker::compatible_types_p (arg_types[i],
-                                            m_compared_func->arg_types[i],
-                                            is_not_leaf, i == 0))
+                                            m_compared_func->arg_types[i]))
        return return_false_with_msg ("argument type is different");
       if (POINTER_TYPE_P (arg_types[i])
          && (TYPE_RESTRICT (arg_types[i])
@@ -427,11 +502,6 @@ sem_function::equals_wpa (sem_item *item,
        return return_false_with_msg ("argument restrict flag mismatch");
     }
 
-  /* Result type checking.  */
-  if (!func_checker::compatible_types_p (result_type,
-                                        m_compared_func->result_type))
-    return return_false_with_msg ("result types are different");
-
   if (node->num_references () != item->node->num_references ())
     return return_false_with_msg ("different number of references");
 
@@ -439,6 +509,24 @@ sem_function::equals_wpa (sem_item *item,
                            TREE_TYPE (item->decl)) != 1)
     return return_false_with_msg ("different type attributes");
 
+  /* The type of THIS pointer type memory location for
+     ipa-polymorphic-call-analysis.  */
+  if (opt_for_fn (decl, flag_devirtualize)
+      && (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE
+          || TREE_CODE (TREE_TYPE (item->decl)) == METHOD_TYPE)
+      && (!flag_ipa_cp
+         || ipa_is_param_used (IPA_NODE_REF (dyn_cast <cgraph_node *>(node)),
+                               0))
+      && compare_polymorphic_p ())
+    {
+      if (TREE_CODE (TREE_TYPE (decl)) != TREE_CODE (TREE_TYPE (item->decl)))
+       return return_false_with_msg ("METHOD_TYPE and FUNCTION_TYPE mismatch");
+      if (!func_checker::compatible_polymorphic_types_p
+          (method_class_type (TREE_TYPE (decl)),
+           method_class_type (TREE_TYPE (item->decl)), false))
+       return return_false_with_msg ("THIS pointer ODR type mismatch");
+    }
+
   ipa_ref *ref = NULL, *ref2 = NULL;
   for (unsigned i = 0; node->iterate_reference (i, ref); i++)
     {
@@ -520,45 +608,6 @@ sem_function::equals_private (sem_item *item,
   if (!equals_wpa (item, ignored_nodes))
     return false;
 
-  /* Checking function TARGET and OPTIMIZATION flags.  */
-  cl_target_option *tar1 = target_opts_for_fn (decl);
-  cl_target_option *tar2 = target_opts_for_fn (m_compared_func->decl);
-
-  if (tar1 != NULL && tar2 != NULL)
-    {
-      if (!cl_target_option_eq (tar1, tar2))
-       {
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           {
-             fprintf (dump_file, "target flags difference");
-             cl_target_option_print_diff (dump_file, 2, tar1, tar2);
-           }
-
-         return return_false_with_msg ("Target flags are different");
-       }
-    }
-  else if (tar1 != NULL || tar2 != NULL)
-    return return_false_with_msg ("Target flags are different");
-
-  cl_optimization *opt1 = opts_for_fn (decl);
-  cl_optimization *opt2 = opts_for_fn (m_compared_func->decl);
-
-  if (opt1 != NULL && opt2 != NULL)
-    {
-      if (memcmp (opt1, opt2, sizeof(cl_optimization)))
-       {
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           {
-             fprintf (dump_file, "optimization flags difference");
-             cl_optimization_print_diff (dump_file, 2, opt1, opt2);
-           }
-
-         return return_false_with_msg ("optimization flags are different");
-       }
-    }
-  else if (opt1 != NULL || opt2 != NULL)
-    return return_false_with_msg ("optimization flags are different");
-
   /* Checking function arguments.  */
   tree decl1 = DECL_ATTRIBUTES (decl);
   tree decl2 = DECL_ATTRIBUTES (m_compared_func->decl);
@@ -598,7 +647,6 @@ sem_function::equals_private (sem_item *item,
   if (decl1 != decl2)
     return return_false();
 
-
   for (arg1 = DECL_ARGUMENTS (decl),
        arg2 = DECL_ARGUMENTS (m_compared_func->decl);
        arg1; arg1 = DECL_CHAIN (arg1), arg2 = DECL_CHAIN (arg2))
@@ -654,30 +702,6 @@ sem_function::equals_private (sem_item *item,
     if (!compare_phi_node (bb_sorted[i]->bb, m_compared_func->bb_sorted[i]->bb))
       return return_false_with_msg ("PHI node comparison returns false");
 
-  /* Compare special function DECL attributes.  */
-  if (DECL_FUNCTION_PERSONALITY (decl) != DECL_FUNCTION_PERSONALITY (item->decl))
-    return return_false_with_msg ("function personalities are different");
-
-  if (DECL_DISREGARD_INLINE_LIMITS (decl) != DECL_DISREGARD_INLINE_LIMITS (item->decl))
-    return return_false_with_msg ("DECL_DISREGARD_INLINE_LIMITS are different");
-
-  if (DECL_DECLARED_INLINE_P (decl) != DECL_DECLARED_INLINE_P (item->decl))
-    return return_false_with_msg ("inline attributes are different");
-
-  if (DECL_IS_OPERATOR_NEW (decl) != DECL_IS_OPERATOR_NEW (item->decl))
-    return return_false_with_msg ("operator new flags are different");
-
-  if (DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl)
-       != DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (item->decl))
-    return return_false_with_msg ("intrument function entry exit "
-                                 "attributes are different");
-
-  if (DECL_NO_LIMIT_STACK (decl) != DECL_NO_LIMIT_STACK (item->decl))
-    return return_false_with_msg ("no stack limit attributes are different");
-
-  if (flags_from_decl_or_type (decl) != flags_from_decl_or_type (item->decl))
-    return return_false_with_msg ("decl_or_type flags are different");
-
   return result;
 }
 
@@ -1224,10 +1248,20 @@ sem_function::hash_stmt (gimple stmt, inchash::hash &hstate)
 bool
 sem_function::compare_polymorphic_p (void)
 {
-  return get_node ()->callees != NULL
-        || get_node ()->indirect_calls != NULL
-        || m_compared_func->get_node ()->callees != NULL
-        || m_compared_func->get_node ()->indirect_calls != NULL;
+  struct cgraph_edge *e;
+
+  if (!opt_for_fn (decl, flag_devirtualize))
+    return false;
+  if (get_node ()->indirect_calls != NULL
+      || m_compared_func->get_node ()->indirect_calls != NULL)
+    return true;
+  /* TODO: We can do simple propagation determining what calls may lead to
+     a polymorphic call.  */
+  for (e = m_compared_func->get_node ()->callees; e; e = e->next_callee)
+    if (e->callee->definition
+       && opt_for_fn (e->callee->decl, flag_devirtualize))
+      return true;
+  return false;
 }
 
 /* For a given call graph NODE, the function constructs new
@@ -1382,41 +1416,6 @@ sem_function::bb_dict_test (vec<int> *bb_dict, int source, int target)
     return (*bb_dict)[source] == target;
 }
 
-/* Iterates all tree types in T1 and T2 and returns true if all types
-   are compatible. If COMPARE_POLYMORPHIC is set to true,
-   more strict comparison is executed.  */
-
-bool
-sem_function::compare_type_list (tree t1, tree t2, bool compare_polymorphic)
-{
-  tree tv1, tv2;
-  tree_code tc1, tc2;
-
-  if (!t1 && !t2)
-    return true;
-
-  while (t1 != NULL && t2 != NULL)
-    {
-      tv1 = TREE_VALUE (t1);
-      tv2 = TREE_VALUE (t2);
-
-      tc1 = TREE_CODE (tv1);
-      tc2 = TREE_CODE (tv2);
-
-      if (tc1 == NOP_EXPR && tc2 == NOP_EXPR)
-       {}
-      else if (tc1 == NOP_EXPR || tc2 == NOP_EXPR)
-       return false;
-      else if (!func_checker::compatible_types_p (tv1, tv2, compare_polymorphic))
-       return false;
-
-      t1 = TREE_CHAIN (t1);
-      t2 = TREE_CHAIN (t2);
-    }
-
-  return !(t1 || t2);
-}
-
 
 /* Semantic variable constructor that uses STACK as bitmap memory stack.  */
 
@@ -1594,8 +1593,7 @@ sem_variable::equals (tree t1, tree t2)
        tree y1 = TREE_OPERAND (t1, 1);
        tree y2 = TREE_OPERAND (t2, 1);
 
-       if (!func_checker::compatible_types_p (TREE_TYPE (x1), TREE_TYPE (x2),
-                                              true))
+       if (!func_checker::compatible_types_p (TREE_TYPE (x1), TREE_TYPE (x2)))
          return return_false ();
 
        /* Type of the offset on MEM_REF does not matter.  */
@@ -1704,8 +1702,7 @@ sem_variable::equals (tree t1, tree t2)
 
     CASE_CONVERT:
     case VIEW_CONVERT_EXPR:
-      if (!func_checker::compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2),
-                                            true))
+      if (!func_checker::compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2)))
          return return_false ();
       return sem_variable::equals (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
     case ERROR_MARK:
@@ -1882,40 +1879,6 @@ sem_variable::dump_to_file (FILE *file)
   fprintf (file, "\n\n");
 }
 
-/* Iterates though a constructor and identifies tree references
-   we are interested in semantic function equality.  */
-
-void
-sem_variable::parse_tree_refs (tree t)
-{
-  switch (TREE_CODE (t))
-    {
-    case CONSTRUCTOR:
-      {
-       unsigned length = vec_safe_length (CONSTRUCTOR_ELTS (t));
-
-       for (unsigned i = 0; i < length; i++)
-         parse_tree_refs(CONSTRUCTOR_ELT (t, i)->value);
-
-       break;
-      }
-    case NOP_EXPR:
-    case ADDR_EXPR:
-      {
-       tree op = TREE_OPERAND (t, 0);
-       parse_tree_refs (op);
-       break;
-      }
-    case FUNCTION_DECL:
-      {
-       tree_refs.safe_push (t);
-       break;
-      }
-    default:
-      break;
-    }
-}
-
 unsigned int sem_item_optimizer::class_id = 0;
 
 sem_item_optimizer::sem_item_optimizer (): worklist (0), m_classes (0),
@@ -2193,10 +2156,7 @@ sem_item_optimizer::filter_removed_items (void)
         {
          cgraph_node *cnode = static_cast <sem_function *>(item)->get_node ();
 
-         bool no_body_function = in_lto_p && (cnode->alias || cnode->body_removed);
-         if (no_body_function || !opt_for_fn (item->decl, flag_ipa_icf_functions)
-             || DECL_CXX_CONSTRUCTOR_P (item->decl)
-             || DECL_CXX_DESTRUCTOR_P (item->decl))
+         if (in_lto_p && (cnode->alias || cnode->body_removed))
            remove_item (item);
          else
            filtered.safe_push (item);
index 1481353..c51bb4a 100644 (file)
@@ -353,11 +353,6 @@ private:
      corresponds to TARGET.  */
   bool bb_dict_test (vec<int> *bb_dict, int source, int target);
 
-  /* Iterates all tree types in T1 and T2 and returns true if all types
-     are compatible. If COMPARE_POLYMORPHIC is set to true,
-     more strict comparison is executed.  */
-  bool compare_type_list (tree t1, tree t2, bool compare_polymorphic);
-
   /* If cgraph edges E1 and E2 are indirect calls, verify that
      ICF flags are the same.  */
   bool compare_edge_flags (cgraph_edge *e1, cgraph_edge *e2);
@@ -415,15 +410,8 @@ public:
   static sem_variable *parse (varpool_node *node, bitmap_obstack *stack);
 
 private:
-  /* Iterates though a constructor and identifies tree references
-     we are interested in semantic function equality.  */
-  void parse_tree_refs (tree t);
-
   /* Compares trees T1 and T2 for semantic equality.  */
   static bool equals (tree t1, tree t2);
-
-  /* Compare that symbol sections are either NULL or have same name.  */
-  bool compare_sections (sem_variable *alias);
 }; // class sem_variable
 
 class sem_item_optimizer;
index d747163..5707f6c 100644 (file)
@@ -3978,6 +3978,9 @@ check_callers (cgraph_node *node, int *max_callers)
 {
   ipa_ref *ref;
 
+  if (!node->can_remove_if_no_direct_calls_and_refs_p ())
+    return true;
+
   for (cgraph_edge *e = node->callers; e; e = e->next_caller)
     {
       (*max_callers)--;
@@ -4007,23 +4010,13 @@ growth_likely_positive (struct cgraph_node *node,
   struct cgraph_edge *e;
   gcc_checking_assert (edge_growth > 0);
 
+  /* First quickly check if NODE is removable at all.  */
   if (DECL_EXTERNAL (node->decl))
     return true;
-  /* Unlike for functions called once, we play unsafe with
-     COMDATs.  We can allow that since we know functions
-     in consideration are small (and thus risk is small) and
-     moreover grow estimates already accounts that COMDAT
-     functions may or may not disappear when eliminated from
-     current unit. With good probability making aggressive
-     choice in all units is going to make overall program
-     smaller.  */
-  if (DECL_COMDAT (node->decl))
-    {
-      if (!node->can_remove_if_no_direct_calls_p ())
-       return true;
-    }
-  else if (!node->will_be_removed_from_program_if_no_direct_calls_p ())
+  if (!node->can_remove_if_no_direct_calls_and_refs_p ()
+      || node->address_taken)
     return true;
+
   max_callers = inline_summaries->get (node)->size * 4 / edge_growth + 2;
 
   for (e = node->callers; e; e = e->next_caller)
@@ -4039,6 +4032,22 @@ growth_likely_positive (struct cgraph_node *node,
     if (check_callers (dyn_cast <cgraph_node *> (ref->referring), &max_callers))
       return true;
 
+  /* Unlike for functions called once, we play unsafe with
+     COMDATs.  We can allow that since we know functions
+     in consideration are small (and thus risk is small) and
+     moreover grow estimates already accounts that COMDAT
+     functions may or may not disappear when eliminated from
+     current unit. With good probability making aggressive
+     choice in all units is going to make overall program
+     smaller.  */
+  if (DECL_COMDAT (node->decl))
+    {
+      if (!node->can_remove_if_no_direct_calls_p ())
+       return true;
+    }
+  else if (!node->will_be_removed_from_program_if_no_direct_calls_p ())
+    return true;
+
   return estimate_growth (node) > 0;
 }
 
index ea0f8b3..d302456 100644 (file)
@@ -80,7 +80,7 @@ bool type_known_to_have_no_deriavations_p (tree);
 bool contains_polymorphic_type_p (const_tree);
 void register_odr_type (tree);
 bool types_must_be_same_for_odr (tree, tree);
-bool types_odr_comparable (tree, tree);
+bool types_odr_comparable (tree, tree, bool strict = false);
 cgraph_node *try_speculative_devirtualization (tree, HOST_WIDE_INT,
                                               ipa_polymorphic_call_context);
 
index 9dfffb6..5d759ca 100644 (file)
@@ -636,8 +636,12 @@ check_pseudos_live_through_calls (int regno)
   if (! sparseset_bit_p (pseudos_live_through_calls, regno))
     return;
   sparseset_clear_bit (pseudos_live_through_calls, regno);
+  bool actual_call_used_reg_set_available_p
+    = !hard_reg_set_empty_p (lra_reg_info[regno].actual_call_used_reg_set);
   IOR_HARD_REG_SET (lra_reg_info[regno].conflict_hard_regs,
-                   call_used_reg_set);
+                   (actual_call_used_reg_set_available_p
+                    ? lra_reg_info[regno].actual_call_used_reg_set
+                    : call_used_reg_set));
 
   for (hr = 0; hr < FIRST_PSEUDO_REGISTER; hr++)
     if (HARD_REGNO_CALL_PART_CLOBBERED (hr, PSEUDO_REGNO_MODE (regno)))
index ce7e6b1..760975f 100644 (file)
@@ -3118,13 +3118,20 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
       fprintf (symtab->dump_file, "Before merging:\n");
       symtab_node::dump_table (symtab->dump_file);
     }
-  lto_symtab_merge_symbols ();
-  /* Removal of unreachable symbols is needed to make verify_symtab to pass;
-     we are still having duplicated comdat groups containing local statics.
-     We could also just remove them while merging.  */
-  symtab->remove_unreachable_nodes (dump_file);
+  if (!flag_ltrans)
+    {
+      lto_symtab_merge_symbols ();
+      /* Removal of unreachable symbols is needed to make verify_symtab to pass;
+        we are still having duplicated comdat groups containing local statics.
+        We could also just remove them while merging.  */
+      symtab->remove_unreachable_nodes (dump_file);
+    }
   ggc_collect ();
   symtab->state = IPA_SSA;
+  /* FIXME: Technically all node removals happening here are useless, because
+     WPA should not stream them.  */
+  if (flag_ltrans)
+    symtab->remove_unreachable_nodes (dump_file);
 
   timevar_pop (TV_IPA_LTO_CGRAPH_MERGE);
 
index 75d6707..2d64a74 100644 (file)
@@ -5514,8 +5514,8 @@ expand_omp_taskreg (struct omp_region *region)
       stmt = gsi_stmt (gsi);
       gcc_assert (stmt && (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
                           || gimple_code (stmt) == GIMPLE_OMP_TASK));
-      gsi_remove (&gsi, true);
       e = split_block (entry_bb, stmt);
+      gsi_remove (&gsi, true);
       entry_bb = e->dest;
       single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
 
@@ -8889,8 +8889,8 @@ expand_omp_target (struct omp_region *region)
       stmt = gsi_stmt (gsi);
       gcc_assert (stmt
                  && gimple_code (stmt) == gimple_code (entry_stmt));
-      gsi_remove (&gsi, true);
       e = split_block (entry_bb, stmt);
+      gsi_remove (&gsi, true);
       entry_bb = e->dest;
       single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
 
index a003b41..5d17498 100644 (file)
@@ -3555,7 +3555,21 @@ simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
          while (GET_MODE (vec) != mode
                 && GET_CODE (vec) == VEC_CONCAT)
            {
-             HOST_WIDE_INT vec_size = GET_MODE_SIZE (GET_MODE (XEXP (vec, 0)));
+             HOST_WIDE_INT vec_size;
+
+             if (CONST_INT_P (XEXP (vec, 0)))
+               {
+                 /* vec_concat of two const_ints doesn't make sense with
+                    respect to modes.  */
+                 if (CONST_INT_P (XEXP (vec, 1)))
+                   return 0;
+
+                 vec_size = GET_MODE_SIZE (GET_MODE (trueop0))
+                            - GET_MODE_SIZE (GET_MODE (XEXP (vec, 1)));
+               }
+             else
+               vec_size = GET_MODE_SIZE (GET_MODE (XEXP (vec, 0)));
+
              if (offset < vec_size)
                vec = XEXP (vec, 0);
              else
index a46ebd4..88e168b 100644 (file)
@@ -1908,3 +1908,106 @@ symtab_node::address_matters_p ()
   gcc_assert (!alias);
   return call_for_symbol_and_aliases (address_matters_1, NULL, true);
 }
+
+/* Return ture if symbol's alignment may be increased.  */
+
+bool
+symtab_node::can_increase_alignment_p (void)
+{
+  symtab_node *target = ultimate_alias_target ();
+
+  /* For now support only variables.  */
+  if (TREE_CODE (decl) != VAR_DECL)
+    return false;
+
+  /* With -fno-toplevel-reorder we may have already output the constant.  */
+  if (TREE_ASM_WRITTEN (target->decl))
+    return false;
+
+  /* If target is already placed in an anchor, we can not touch its
+     alignment.  */
+  if (DECL_RTL_SET_P (target->decl)
+      && MEM_P (DECL_RTL (target->decl))
+      && SYMBOL_REF_HAS_BLOCK_INFO_P (XEXP (DECL_RTL (target->decl), 0)))
+    return false;
+
+  /* Constant pool entries may be shared.  */
+  if (DECL_IN_CONSTANT_POOL (target->decl))
+    return false;
+
+  /* We cannot change alignment of symbols that may bind to symbols
+     in other translation unit that may contain a definition with lower
+     alignment.  */
+  if (!decl_binds_to_current_def_p (decl))
+    return false;
+
+  /* When compiling partition, be sure the symbol is not output by other
+     partition.  */
+  if (flag_ltrans
+      && (target->in_other_partition
+         || target->get_partitioning_class () == SYMBOL_DUPLICATE))
+    return false;
+
+  /* Do not override the alignment as specified by the ABI when the used
+     attribute is set.  */
+  if (DECL_PRESERVE_P (decl) || DECL_PRESERVE_P (target->decl))
+    return false;
+
+  /* Do not override explicit alignment set by the user when an explicit
+     section name is also used.  This is a common idiom used by many
+     software projects.  */
+  if (DECL_SECTION_NAME (target->decl) != NULL && !target->implicit_section)
+    return false;
+
+  return true;
+}
+
+/* Worker for symtab_node::increase_alignment.  */
+
+static bool
+increase_alignment_1 (symtab_node *n, void *v)
+{
+  unsigned int align = (size_t)v;
+  if (DECL_ALIGN (n->decl) < align
+      && n->can_increase_alignment_p ())
+    {
+      DECL_ALIGN (n->decl) = align;
+      DECL_USER_ALIGN (n->decl) = 1;
+    }
+  return false;
+}
+
+/* Increase alignment of THIS to ALIGN.  */
+
+void
+symtab_node::increase_alignment (unsigned int align)
+{
+  gcc_assert (can_increase_alignment_p () && align < MAX_OFILE_ALIGNMENT);
+  ultimate_alias_target()->call_for_symbol_and_aliases (increase_alignment_1,
+                                                       (void *)(size_t) align,
+                                                       true);
+  gcc_assert (DECL_ALIGN (decl) >= align);
+}
+
+/* Helper for symtab_node::definition_alignment.  */
+
+static bool
+get_alignment_1 (symtab_node *n, void *v)
+{
+  *((unsigned int *)v) = MAX (*((unsigned int *)v), DECL_ALIGN (n->decl));
+  return false;
+}
+
+/* Return desired alignment of the definition.  This is NOT alignment useful
+   to access THIS, because THIS may be interposable and DECL_ALIGN should
+   be used instead.  It however must be guaranteed when output definition
+   of THIS.  */
+
+unsigned int
+symtab_node::definition_alignment ()
+{
+  unsigned int align = 0;
+  gcc_assert (!alias);
+  call_for_symbol_and_aliases (get_alignment_1, &align, true);
+  return align;
+}
index 99cf180..b06eed3 100644 (file)
@@ -1375,7 +1375,17 @@ process_options (void)
   if (flag_check_pointer_bounds)
     {
       if (targetm.chkp_bound_mode () == VOIDmode)
-       error ("-fcheck-pointer-bounds is not supported for this target");
+       {
+         error ("-fcheck-pointer-bounds is not supported for this target");
+         flag_check_pointer_bounds = 0;
+       }
+
+      if (flag_sanitize & SANITIZE_ADDRESS)
+       {
+         error ("-fcheck-pointer-bounds is not supported with "
+                "Address Sanitizer");
+         flag_check_pointer_bounds = 0;
+       }
     }
 
   /* One region RA really helps to decrease the code size.  */
index 006bc08..0f5e428 100644 (file)
@@ -1703,7 +1703,8 @@ gimple_can_merge_blocks_p (basic_block a, basic_block b)
   if (!single_pred_p (b))
     return false;
 
-  if (b == EXIT_BLOCK_PTR_FOR_FN (cfun))
+  if (a == ENTRY_BLOCK_PTR_FOR_FN (cfun)
+      || b == EXIT_BLOCK_PTR_FOR_FN (cfun))
     return false;
 
   /* If A ends by a statement causing exceptions or something similar, we
@@ -5683,7 +5684,6 @@ gimple_split_block (basic_block bb, void *stmt)
 {
   gimple_stmt_iterator gsi;
   gimple_stmt_iterator gsi_tgt;
-  gimple act;
   gimple_seq list;
   basic_block new_bb;
   edge e;
@@ -5697,26 +5697,16 @@ gimple_split_block (basic_block bb, void *stmt)
   FOR_EACH_EDGE (e, ei, new_bb->succs)
     e->src = new_bb;
 
-  if (stmt && gimple_code ((gimple) stmt) == GIMPLE_LABEL)
-    stmt = NULL;
-
-  /* Move everything from GSI to the new basic block.  */
-  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+  /* Get a stmt iterator pointing to the first stmt to move.  */
+  if (!stmt || gimple_code ((gimple) stmt) == GIMPLE_LABEL)
+    gsi = gsi_after_labels (bb);
+  else
     {
-      act = gsi_stmt (gsi);
-      if (gimple_code (act) == GIMPLE_LABEL)
-       continue;
-
-      if (!stmt)
-       break;
-
-      if (stmt == act)
-       {
-         gsi_next (&gsi);
-         break;
-       }
+      gsi = gsi_for_stmt ((gimple) stmt);
+      gsi_next (&gsi);
     }
-
+  /* Move everything from GSI to the new basic block.  */
   if (gsi_end_p (gsi))
     return new_bb;
 
@@ -8732,10 +8722,6 @@ execute_fixup_cfg (void)
   if (count_scale != REG_BR_PROB_BASE)
     compute_function_frequency ();
 
-  /* Dump a textual representation of the flowgraph.  */
-  if (dump_file)
-    gimple_dump_cfg (dump_file, dump_flags);
-
   if (current_loops
       && (todo & TODO_cleanup_cfg))
     loops_state_set (LOOPS_NEED_FIXUP);
@@ -8748,7 +8734,7 @@ namespace {
 const pass_data pass_data_fixup_cfg =
 {
   GIMPLE_PASS, /* type */
-  "*free_cfg_annotations", /* name */
+  "fixup_cfg", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
   TV_NONE, /* tv_id */
   PROP_cfg, /* properties_required */
index 5c5c7ba..e7122e3 100644 (file)
@@ -625,35 +625,13 @@ fixup_noreturn_call (gimple stmt)
       update_stmt (stmt);
     }
 
+  /* Mark the call as altering control flow.  */
+  gimple_call_set_ctrl_altering (stmt, true);
+
   return remove_fallthru_edge (bb->succs);
 }
 
 
-/* Split basic blocks on calls in the middle of a basic block that are now
-   known not to return, and remove the unreachable code.  */
-
-static bool
-split_bb_on_noreturn_calls (basic_block bb)
-{
-  bool changed = false;
-  gimple_stmt_iterator gsi;
-
-  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-    {
-      gimple stmt = gsi_stmt (gsi);
-
-      if (!is_gimple_call (stmt))
-       continue;
-
-      if (gimple_call_noreturn_p (stmt))
-       changed |= fixup_noreturn_call (stmt);
-    }
-
-  if (changed)
-    bitmap_set_bit (cfgcleanup_altered_bbs, bb->index);
-  return changed;
-}
-
 /* Tries to cleanup cfg in basic block BB.  Returns true if anything
    changes.  */
 
@@ -672,8 +650,18 @@ cleanup_tree_cfg_bb (basic_block bb)
   if (single_succ_p (bb)
       && can_merge_blocks_p (bb, single_succ (bb)))
     {
-      merge_blocks (bb, single_succ (bb));
-      return true;
+      /* If there is a merge opportunity with the predecessor
+         do nothing now but wait until we process the predecessor.
+        This happens when we visit BBs in a non-optimal order and
+        avoids quadratic behavior with adjusting stmts BB pointer.  */
+      if (single_pred_p (bb)
+         && can_merge_blocks_p (single_pred (bb), bb))
+       ;
+      else
+       {
+         merge_blocks (bb, single_succ (bb));
+         return true;
+       }
     }
 
   return retval;
@@ -703,10 +691,7 @@ cleanup_tree_cfg_1 (void)
     {
       bb = BASIC_BLOCK_FOR_FN (cfun, i);
       if (bb)
-       {
-         retval |= cleanup_tree_cfg_bb (bb);
-         retval |= split_bb_on_noreturn_calls (bb);
-       }
+       retval |= cleanup_tree_cfg_bb (bb);
     }
 
   /* Now process the altered blocks, as long as any are available.  */
@@ -722,10 +707,6 @@ cleanup_tree_cfg_1 (void)
        continue;
 
       retval |= cleanup_tree_cfg_bb (bb);
-
-      /* Rerun split_bb_on_noreturn_calls, in case we have altered any noreturn
-        calls.  */
-      retval |= split_bb_on_noreturn_calls (bb);
     }
 
   end_recording_case_labels ();
@@ -1111,9 +1092,12 @@ make_pass_merge_phi (gcc::context *ctxt)
 static unsigned int
 execute_cleanup_cfg_post_optimizing (void)
 {
-  unsigned int todo = 0;
+  unsigned int todo = execute_fixup_cfg ();
   if (cleanup_tree_cfg ())
-    todo |= TODO_update_ssa;
+    {
+      todo &= ~TODO_cleanup_cfg;
+      todo |= TODO_update_ssa;
+    }
   maybe_remove_unreachable_handlers ();
   cleanup_dead_labels ();
   group_case_labels ();
index 3aaf650..ad1bb23 100644 (file)
@@ -700,7 +700,8 @@ enum size_type_kind {
 enum operand_equal_flag {
   OEP_ONLY_CONST = 1,
   OEP_PURE_SAME = 2,
-  OEP_CONSTANT_ADDRESS_OF = 4
+  OEP_CONSTANT_ADDRESS_OF = 4,
+  OEP_ADDRESS_OF = 8
 };
 
 /* Enum and arrays used for tree allocation stats.
index d8abe03..83e4335 100644 (file)
@@ -2805,7 +2805,9 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency_scale,
          maybe_move_debug_stmts_to_successors (id, (basic_block) bb->aux);
        /* Update call edge destinations.  This can not be done before loop
           info is updated, because we may split basic blocks.  */
-       if (id->transform_call_graph_edges == CB_CGE_DUPLICATE)
+       if (id->transform_call_graph_edges == CB_CGE_DUPLICATE
+           && bb->index != ENTRY_BLOCK
+           && bb->index != EXIT_BLOCK)
          redirect_all_calls (id, (basic_block)bb->aux);
        ((basic_block)bb->aux)->aux = NULL;
        bb->aux = NULL;
@@ -4777,18 +4779,19 @@ static bool
 gimple_expand_calls_inline (basic_block bb, copy_body_data *id)
 {
   gimple_stmt_iterator gsi;
+  bool inlined = false;
 
-  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+  for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi);)
     {
       gimple stmt = gsi_stmt (gsi);
+      gsi_prev (&gsi);
 
       if (is_gimple_call (stmt)
-         && !gimple_call_internal_p (stmt)
-         && expand_call_inline (bb, stmt, id))
-       return true;
+         && !gimple_call_internal_p (stmt))
+       inlined |= expand_call_inline (bb, stmt, id);
     }
 
-  return false;
+  return inlined;
 }
 
 
index 5f7c1bc..fbb9eeb 100644 (file)
@@ -1111,7 +1111,8 @@ create_call_for_reduction_1 (reduction_info **slot, struct clsn_data *clsn_data)
   /* Create phi node.  */
   bb = clsn_data->load_bb;
 
-  e = split_block (bb, t);
+  gsi = gsi_last_bb (bb);
+  e = split_block (bb, gsi_stmt (gsi));
   new_bb = e->dest;
 
   tmp_load = create_tmp_var (TREE_TYPE (TREE_TYPE (addr)));
index 3527a47..a49e950 100644 (file)
@@ -1597,7 +1597,7 @@ build_ref_for_offset (location_t loc, tree base, HOST_WIDE_INT offset,
   misalign = (misalign + offset) & (align - 1);
   if (misalign != 0)
     align = (misalign & -misalign);
-  if (align < TYPE_ALIGN (exp_type))
+  if (align != TYPE_ALIGN (exp_type))
     exp_type = build_aligned_type (exp_type, align);
 
   mem_ref = fold_build2_loc (loc, MEM_REF, exp_type, base, off);
index 1afeefe..dd6b9c0 100644 (file)
@@ -59,6 +59,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-live.h"
 #include "tree-ssa-coalesce.h"
 #include "diagnostic-core.h"
+#include "timevar.h"
 
 
 /* This set of routines implements a coalesce_list.  This is an object which
@@ -1121,8 +1122,8 @@ create_outofssa_var_map (coalesce_list_p cl, bitmap used_in_copy)
 
 
 /* Attempt to coalesce ssa versions X and Y together using the partition
-   mapping in MAP and checking conflicts in GRAPH.  Output any debug info to
-   DEBUG, if it is nun-NULL.  */
+   mapping in MAP and checking conflicts in GRAPH if not NULL.
+   Output any debug info to DEBUG, if it is nun-NULL.  */
 
 static inline bool
 attempt_coalesce (var_map map, ssa_conflicts_p graph, int x, int y,
@@ -1154,7 +1155,8 @@ attempt_coalesce (var_map map, ssa_conflicts_p graph, int x, int y,
     fprintf (debug, " [map: %d, %d] ", p1, p2);
 
 
-  if (!ssa_conflicts_test_p (graph, p1, p2))
+  if (!graph
+      || !ssa_conflicts_test_p (graph, p1, p2))
     {
       var1 = partition_to_var (map, p1);
       var2 = partition_to_var (map, p2);
@@ -1168,10 +1170,13 @@ attempt_coalesce (var_map map, ssa_conflicts_p graph, int x, int y,
 
       /* z is the new combined partition.  Remove the other partition from
         the list, and merge the conflicts.  */
-      if (z == p1)
-       ssa_conflicts_merge (graph, p1, p2);
-      else
-       ssa_conflicts_merge (graph, p2, p1);
+      if (graph)
+       {
+         if (z == p1)
+           ssa_conflicts_merge (graph, p1, p2);
+         else
+           ssa_conflicts_merge (graph, p2, p1);
+       }
 
       if (debug)
        fprintf (debug, ": Success -> %d\n", z);
@@ -1185,24 +1190,16 @@ attempt_coalesce (var_map map, ssa_conflicts_p graph, int x, int y,
 }
 
 
-/* Attempt to Coalesce partitions in MAP which occur in the list CL using
-   GRAPH.  Debug output is sent to DEBUG if it is non-NULL.  */
+/* Perform all abnormal coalescing on MAP.
+   Debug output is sent to DEBUG if it is non-NULL.  */
 
 static void
-coalesce_partitions (var_map map, ssa_conflicts_p graph, coalesce_list_p cl,
-                    FILE *debug)
+perform_abnormal_coalescing (var_map map, FILE *debug)
 {
-  int x = 0, y = 0;
-  tree var1, var2;
-  int cost;
   basic_block bb;
   edge e;
   edge_iterator ei;
 
-  /* First, coalesce all the copies across abnormal edges.  These are not placed
-     in the coalesce list because they do not need to be sorted, and simply
-     consume extra memory/compilation time in large programs.  */
-
   FOR_EACH_BB_FN (bb, cfun)
     {
       FOR_EACH_EDGE (e, ei, bb->preds)
@@ -1226,11 +1223,23 @@ coalesce_partitions (var_map map, ssa_conflicts_p graph, coalesce_list_p cl,
                if (debug)
                  fprintf (debug, "Abnormal coalesce: ");
 
-               if (!attempt_coalesce (map, graph, v1, v2, debug))
+               if (!attempt_coalesce (map, NULL, v1, v2, debug))
                  fail_abnormal_edge_coalesce (v1, v2);
              }
          }
     }
+}
+
+/* Attempt to Coalesce partitions in MAP which occur in the list CL using
+   GRAPH.  Debug output is sent to DEBUG if it is non-NULL.  */
+
+static void
+coalesce_partitions (var_map map, ssa_conflicts_p graph, coalesce_list_p cl,
+                    FILE *debug)
+{
+  int x = 0, y = 0;
+  tree var1, var2;
+  int cost;
 
   /* Now process the items in the coalesce list.  */
 
@@ -1285,6 +1294,11 @@ coalesce_ssa_name (void)
   var_map map;
   unsigned int i;
 
+#ifdef ENABLE_CHECKING
+  /* Verify we can perform all must coalesces.  */
+  verify_ssa_coalescing ();
+#endif
+
   cl = create_coalesce_list ();
   map = create_outofssa_var_map (cl, used_in_copies);
 
@@ -1341,6 +1355,15 @@ coalesce_ssa_name (void)
       return map;
     }
 
+  /* First, coalesce all the copies across abnormal edges.  These are not placed
+     in the coalesce list because they do not need to be sorted, and simply
+     consume extra memory/compilation time in large programs.
+     Performing abnormal coalescing also needs no live/conflict computation
+     because it must succeed (but we lose checking that it indeed does).
+     Still for PR63155 this reduces memory usage from 10GB to zero.  */
+  perform_abnormal_coalescing (map,
+                              ((dump_flags & TDF_DETAILS) ? dump_file : NULL));
+
   if (dump_file && (dump_flags & TDF_DETAILS))
     dump_var_map (dump_file, map);
 
@@ -1371,11 +1394,100 @@ coalesce_ssa_name (void)
 
   /* Now coalesce everything in the list.  */
   coalesce_partitions (map, graph, cl,
-                      ((dump_flags & TDF_DETAILS) ? dump_file
-                                                  : NULL));
+                      ((dump_flags & TDF_DETAILS) ? dump_file : NULL));
 
   delete_coalesce_list (cl);
   ssa_conflicts_delete (graph);
 
   return map;
 }
+
+
+/* Helper for verify_ssa_coalescing.  Operates in two modes:
+   1) scan the function for coalesces we must perform and store the
+      SSA names participating in USED_IN_COPIES
+   2) scan the function for coalesces and verify they can be performed
+      under the constraints of GRAPH updating MAP in the process
+   FIXME:  This can be extended to verify that the virtual operands
+   form a factored use-def chain (coalescing the active virtual use
+   with the virtual def at virtual def point).  */
+
+static void
+verify_ssa_coalescing_worker (bitmap used_in_copies,
+                             var_map map, ssa_conflicts_p graph)
+{
+  basic_block bb;
+
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      edge e;
+      edge_iterator ei;
+
+      FOR_EACH_EDGE (e, ei, bb->preds)
+       if (e->flags & EDGE_ABNORMAL)
+         {
+           gphi_iterator gsi;
+           for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
+                gsi_next (&gsi))
+             {
+               gphi *phi = gsi.phi ();
+               tree arg = PHI_ARG_DEF (phi, e->dest_idx);
+               if (SSA_NAME_IS_DEFAULT_DEF (arg)
+                   && (!SSA_NAME_VAR (arg)
+                       || TREE_CODE (SSA_NAME_VAR (arg)) != PARM_DECL))
+                 continue;
+
+               tree res = PHI_RESULT (phi);
+
+               int v1 = SSA_NAME_VERSION (res);
+               int v2 = SSA_NAME_VERSION (arg);
+               if (used_in_copies)
+                 {
+                   bitmap_set_bit (used_in_copies, v1);
+                   bitmap_set_bit (used_in_copies, v2);
+                 }
+               else
+                 {
+                   int p1 = var_to_partition (map, res);
+                   int p2 = var_to_partition (map, arg);
+                   if (p1 != p2)
+                     {
+                       if (ssa_conflicts_test_p (graph, p1, p2))
+                         fail_abnormal_edge_coalesce (v1, v2);
+                       int z = var_union (map,
+                                          partition_to_var (map, p1),
+                                          partition_to_var (map, p2));
+                       if (z == p1)
+                         ssa_conflicts_merge (graph, p1, p2);
+                       else
+                         ssa_conflicts_merge (graph, p2, p1);
+                     }
+                 }
+             }
+         }
+    }
+}
+
+/* Verify that we can coalesce SSA names we must coalesce.  */
+
+DEBUG_FUNCTION void
+verify_ssa_coalescing (void)
+{
+  auto_timevar tv (TV_TREE_SSA_VERIFY);
+  bitmap used_in_copies = BITMAP_ALLOC (NULL);
+  verify_ssa_coalescing_worker (used_in_copies, NULL, NULL);
+  if (bitmap_empty_p (used_in_copies))
+    {
+      BITMAP_FREE (used_in_copies);
+      return;
+    }
+  var_map map = init_var_map (num_ssa_names);
+  partition_view_bitmap (map, used_in_copies, true);
+  BITMAP_FREE (used_in_copies);
+  tree_live_info_p liveinfo = calculate_live_ranges (map, false);
+  ssa_conflicts_p graph = build_ssa_conflict_graph (liveinfo);
+  delete_tree_live_info (liveinfo);
+  verify_ssa_coalescing_worker (NULL, map, graph);
+  ssa_conflicts_delete (graph);
+  delete_var_map (map);
+}
index 99b188a..06c33bf 100644 (file)
@@ -21,5 +21,6 @@ along with GCC; see the file COPYING3.  If not see
 #define GCC_TREE_SSA_COALESCE_H
 
 extern var_map coalesce_ssa_name (void);
+extern void verify_ssa_coalescing (void);
 
 #endif /* GCC_TREE_SSA_COALESCE_H */
index d230ce1..ea49eb7 100644 (file)
@@ -74,6 +74,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-dom.h"
 #include "inchash.h"
 #include "gimplify.h"
+#include "tree-cfgcleanup.h"
 
 /* This file implements optimizations on the dominator tree.  */
 
@@ -246,6 +247,7 @@ static bool cfg_altered;
 /* Bitmap of blocks that have had EH statements cleaned.  We should
    remove their dead edges eventually.  */
 static bitmap need_eh_cleanup;
+static vec<gimple> need_noreturn_fixup;
 
 /* Statistics for dominator optimizations.  */
 struct opt_stats_d
@@ -885,6 +887,7 @@ pass_dominator::execute (function *fun)
   avail_exprs_stack.create (20);
   const_and_copies_stack.create (20);
   need_eh_cleanup = BITMAP_ALLOC (NULL);
+  need_noreturn_fixup.create (0);
 
   calculate_dominance_info (CDI_DOMINATORS);
   cfg_altered = false;
@@ -967,6 +970,23 @@ pass_dominator::execute (function *fun)
       bitmap_clear (need_eh_cleanup);
     }
 
+  /* Fixup stmts that became noreturn calls.  This may require splitting
+     blocks and thus isn't possible during the dominator walk or before
+     jump threading finished.  Do this in reverse order so we don't
+     inadvertedly remove a stmt we want to fixup by visiting a dominating
+     now noreturn call first.  */
+  while (!need_noreturn_fixup.is_empty ())
+    {
+      gimple stmt = need_noreturn_fixup.pop ();
+      if (dump_file && dump_flags & TDF_DETAILS)
+       {
+         fprintf (dump_file, "Fixing up noreturn call ");
+         print_gimple_stmt (dump_file, stmt, 0, 0);
+         fprintf (dump_file, "\n");
+       }
+      fixup_noreturn_call (stmt);
+    }
+
   statistics_counter_event (fun, "Redundant expressions eliminated",
                            opt_stats.num_re);
   statistics_counter_event (fun, "Constants propagated",
@@ -986,7 +1006,7 @@ pass_dominator::execute (function *fun)
 
   /* Free asserted bitmaps and stacks.  */
   BITMAP_FREE (need_eh_cleanup);
-
+  need_noreturn_fixup.release ();
   avail_exprs_stack.release ();
   const_and_copies_stack.release ();
 
@@ -2364,8 +2384,10 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si)
   gimple stmt, old_stmt;
   bool may_optimize_p;
   bool modified_p = false;
+  bool was_noreturn;
 
   old_stmt = stmt = gsi_stmt (si);
+  was_noreturn = is_gimple_call (stmt) && gimple_call_noreturn_p (stmt);
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -2545,6 +2567,10 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si)
          if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, "  Flagged to clear EH edges.\n");
        }
+
+      if (!was_noreturn
+         && is_gimple_call (stmt) && gimple_call_noreturn_p (stmt))
+       need_noreturn_fixup.safe_push (stmt);
     }
 }
 
index d8db20a..93f92f3 100644 (file)
@@ -2141,6 +2141,7 @@ pass_forwprop::execute (function *fun)
   lattice.quick_grow_cleared (num_ssa_names);
   int *postorder = XNEWVEC (int, n_basic_blocks_for_fn (fun));
   int postorder_num = inverted_post_order_compute (postorder);
+  auto_vec<gimple, 4> to_fixup;
   to_purge = BITMAP_ALLOC (NULL);
   for (int i = 0; i < postorder_num; ++i)
     {
@@ -2340,6 +2341,8 @@ pass_forwprop::execute (function *fun)
          gimple stmt = gsi_stmt (gsi);
          gimple orig_stmt = stmt;
          bool changed = false;
+         bool was_noreturn = (is_gimple_call (stmt)
+                              && gimple_call_noreturn_p (stmt));
 
          /* Mark stmt as potentially needing revisiting.  */
          gimple_set_plf (stmt, GF_PLF_1, false);
@@ -2350,6 +2353,9 @@ pass_forwprop::execute (function *fun)
              stmt = gsi_stmt (gsi);
              if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt))
                bitmap_set_bit (to_purge, bb->index);
+             if (!was_noreturn
+                 && is_gimple_call (stmt) && gimple_call_noreturn_p (stmt))
+               to_fixup.safe_push (stmt);
              /* Cleanup the CFG if we simplified a condition to
                 true or false.  */
              if (gcond *cond = dyn_cast <gcond *> (stmt))
@@ -2470,6 +2476,22 @@ pass_forwprop::execute (function *fun)
   free (postorder);
   lattice.release ();
 
+  /* Fixup stmts that became noreturn calls.  This may require splitting
+     blocks and thus isn't possible during the walk.  Do this
+     in reverse order so we don't inadvertedly remove a stmt we want to
+     fixup by visiting a dominating now noreturn call first.  */
+  while (!to_fixup.is_empty ())
+    {
+      gimple stmt = to_fixup.pop ();
+      if (dump_file && dump_flags & TDF_DETAILS)
+       {
+         fprintf (dump_file, "Fixing up noreturn call ");
+         print_gimple_stmt (dump_file, stmt, 0, 0);
+         fprintf (dump_file, "\n");
+       }
+      cfg_changed |= fixup_noreturn_call (stmt);
+    }
+
   cfg_changed |= gimple_purge_all_dead_eh_edges (to_purge);
   BITMAP_FREE (to_purge);
 
index 83b48df..c985e79 100644 (file)
@@ -98,6 +98,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-prop.h"
 #include "tree-ssa-propagate.h"
 #include "ipa-utils.h"
+#include "tree-cfgcleanup.h"
 
 /* TODO:
 
@@ -3922,6 +3923,7 @@ compute_avail (void)
 
 /* Local state for the eliminate domwalk.  */
 static vec<gimple> el_to_remove;
+static vec<gimple> el_to_fixup;
 static unsigned int el_todo;
 static vec<tree> el_avail;
 static vec<tree> el_avail_stack;
@@ -4429,7 +4431,7 @@ eliminate_dom_walker::before_dom_children (basic_block b)
              /* When changing a call into a noreturn call, cfg cleanup
                 is needed to fix up the noreturn call.  */
              if (!was_noreturn && gimple_call_noreturn_p (stmt))
-               el_todo |= TODO_cleanup_cfg;
+               el_to_fixup.safe_push  (stmt);
            }
          else
            {
@@ -4529,6 +4531,7 @@ eliminate (bool do_pre)
   need_ab_cleanup = BITMAP_ALLOC (NULL);
 
   el_to_remove.create (0);
+  el_to_fixup.create (0);
   el_todo = 0;
   el_avail.create (num_ssa_names);
   el_avail_stack.create (0);
@@ -4580,6 +4583,25 @@ eliminate (bool do_pre)
     }
   el_to_remove.release ();
 
+  /* Fixup stmts that became noreturn calls.  This may require splitting
+     blocks and thus isn't possible during the dominator walk.  Do this
+     in reverse order so we don't inadvertedly remove a stmt we want to
+     fixup by visiting a dominating now noreturn call first.  */
+  while (!el_to_fixup.is_empty ())
+    {
+      stmt = el_to_fixup.pop ();
+
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "Fixing up noreturn call ");
+         print_gimple_stmt (dump_file, stmt, 0, 0);
+       }
+
+      if (fixup_noreturn_call (stmt))
+       el_todo |= TODO_cleanup_cfg;
+    }
+  el_to_fixup.release ();
+
   return el_todo;
 }
 
index 8b82f9e..c3f9d3e 100644 (file)
@@ -67,6 +67,7 @@
 #include "value-prof.h"
 #include "domwalk.h"
 #include "cfgloop.h"
+#include "tree-cfgcleanup.h"
 
 /* This file implements a generic value propagation engine based on
    the same propagation used by the SSA-CCP algorithm [1].
@@ -1071,11 +1072,13 @@ public:
       fold_fn (fold_fn_), do_dce (do_dce_), something_changed (false)
     {
       stmts_to_remove.create (0);
+      stmts_to_fixup.create (0);
       need_eh_cleanup = BITMAP_ALLOC (NULL);
     }
     ~substitute_and_fold_dom_walker ()
     {
       stmts_to_remove.release ();
+      stmts_to_fixup.release ();
       BITMAP_FREE (need_eh_cleanup);
     }
 
@@ -1087,6 +1090,7 @@ public:
     bool do_dce;
     bool something_changed;
     vec<gimple> stmts_to_remove;
+    vec<gimple> stmts_to_fixup;
     bitmap need_eh_cleanup;
 };
 
@@ -1125,7 +1129,6 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
     {
       bool did_replace;
       gimple stmt = gsi_stmt (i);
-      gimple old_stmt;
       enum gimple_code code = gimple_code (stmt);
 
       /* Ignore ASSERT_EXPRs.  They are used by VRP to generate
@@ -1163,7 +1166,9 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
          print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
        }
 
-      old_stmt = stmt;
+      gimple old_stmt = stmt;
+      bool was_noreturn = (is_gimple_call (stmt)
+                          && gimple_call_noreturn_p (stmt));
 
       /* Some statements may be simplified using propagator
         specific information.  Do this before propagating
@@ -1194,6 +1199,13 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
          if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
            bitmap_set_bit (need_eh_cleanup, bb->index);
 
+         /* If we turned a not noreturn call into a noreturn one
+            schedule it for fixup.  */
+         if (!was_noreturn
+             && is_gimple_call (stmt)
+             && gimple_call_noreturn_p (stmt))
+           stmts_to_fixup.safe_push (stmt);
+
          if (is_gimple_assign (stmt)
              && (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
                  == GIMPLE_SINGLE_RHS))
@@ -1286,6 +1298,22 @@ substitute_and_fold (ssa_prop_get_value_fn get_value_fn,
   if (!bitmap_empty_p (walker.need_eh_cleanup))
     gimple_purge_all_dead_eh_edges (walker.need_eh_cleanup);
 
+  /* Fixup stmts that became noreturn calls.  This may require splitting
+     blocks and thus isn't possible during the dominator walk.  Do this
+     in reverse order so we don't inadvertedly remove a stmt we want to
+     fixup by visiting a dominating now noreturn call first.  */
+  while (!walker.stmts_to_fixup.is_empty ())
+    {
+      gimple stmt = walker.stmts_to_fixup.pop ();
+      if (dump_file && dump_flags & TDF_DETAILS)
+       {
+         fprintf (dump_file, "Fixing up noreturn call ");
+         print_gimple_stmt (dump_file, stmt, 0, 0);
+         fprintf (dump_file, "\n");
+       }
+      fixup_noreturn_call (stmt);
+    }
+
   statistics_counter_event (cfun, "Constants propagated",
                            prop_stats.num_const_prop);
   statistics_counter_event (cfun, "Copies propagated",
index 5d47813..2c48cb6 100644 (file)
@@ -587,7 +587,7 @@ same_succ_def::equal (const value_type *e1, const compare_type *e2)
   if (!inverse_flags (e1, e2))
     {
       for (i = 0; i < e1->succ_flags.length (); ++i)
-       if (e1->succ_flags[i] != e1->succ_flags[i])
+       if (e1->succ_flags[i] != e2->succ_flags[i])
          return 0;
     }
 
index ffe83e2..b308ac7 100644 (file)
@@ -758,12 +758,7 @@ vect_compute_data_ref_alignment (struct data_reference *dr)
          && TREE_CODE (TREE_OPERAND (base, 0)) == ADDR_EXPR)
        base = TREE_OPERAND (TREE_OPERAND (base, 0), 0);
 
-      /* Do not change the alignment of global variables here if
-        flag_section_anchors is enabled as we already generated
-        RTL for other functions.  Most global variables should
-        have been aligned during the IPA increase_alignment pass.  */
-      if (!vect_can_force_dr_alignment_p (base, TYPE_ALIGN (vectype))
-         || (TREE_STATIC (base) && flag_section_anchors))
+      if (!vect_can_force_dr_alignment_p (base, TYPE_ALIGN (vectype)))
        {
          if (dump_enabled_p ())
            {
@@ -5703,58 +5698,10 @@ vect_can_force_dr_alignment_p (const_tree decl, unsigned int alignment)
   if (TREE_CODE (decl) != VAR_DECL)
     return false;
 
-  /* With -fno-toplevel-reorder we may have already output the constant.  */
-  if (TREE_ASM_WRITTEN (decl))
+  if (decl_in_symtab_p (decl)
+      && !symtab_node::get (decl)->can_increase_alignment_p ())
     return false;
 
-  /* Constant pool entries may be shared and not properly merged by LTO.  */
-  if (DECL_IN_CONSTANT_POOL (decl))
-    return false;
-
-  if (TREE_PUBLIC (decl) || DECL_EXTERNAL (decl))
-    {
-      symtab_node *snode;
-
-      /* We cannot change alignment of symbols that may bind to symbols
-        in other translation unit that may contain a definition with lower
-        alignment.  */
-      if (!decl_binds_to_current_def_p (decl))
-       return false;
-
-      /* When compiling partition, be sure the symbol is not output by other
-        partition.  */
-      snode = symtab_node::get (decl);
-      if (flag_ltrans
-         && (snode->in_other_partition
-             || snode->get_partitioning_class () == SYMBOL_DUPLICATE))
-       return false;
-    }
-
-  /* Do not override the alignment as specified by the ABI when the used
-     attribute is set.  */
-  if (DECL_PRESERVE_P (decl))
-    return false;
-
-  /* Do not override explicit alignment set by the user when an explicit
-     section name is also used.  This is a common idiom used by many
-     software projects.  */
-  if (TREE_STATIC (decl) 
-      && DECL_SECTION_NAME (decl) != NULL
-      && !symtab_node::get (decl)->implicit_section)
-    return false;
-
-  /* If symbol is an alias, we need to check that target is OK.  */
-  if (TREE_STATIC (decl))
-    {
-      tree target = symtab_node::get (decl)->ultimate_alias_target ()->decl;
-      if (target != decl)
-       {
-         if (DECL_PRESERVE_P (target))
-           return false;
-         decl = target;
-       }
-    }
-
   if (TREE_STATIC (decl))
     return (alignment <= MAX_OFILE_ALIGNMENT);
   else
index aa9d43f..41ff802 100644 (file)
@@ -4956,8 +4956,13 @@ ensure_base_align (stmt_vec_info stmt_info, struct data_reference *dr)
       tree vectype = STMT_VINFO_VECTYPE (stmt_info);
       tree base_decl = ((dataref_aux *)dr->aux)->base_decl;
 
-      DECL_ALIGN (base_decl) = TYPE_ALIGN (vectype);
-      DECL_USER_ALIGN (base_decl) = 1;
+      if (decl_in_symtab_p (base_decl))
+       symtab_node::get (base_decl)->increase_alignment (TYPE_ALIGN (vectype));
+      else
+       {
+          DECL_ALIGN (base_decl) = TYPE_ALIGN (vectype);
+          DECL_USER_ALIGN (base_decl) = 1;
+       }
       ((dataref_aux *)dr->aux)->base_misaligned = false;
     }
 }
index 5d43720..415bffa 100644 (file)
@@ -719,14 +719,7 @@ increase_alignment (void)
 
       if (vect_can_force_dr_alignment_p (decl, alignment))
         {
-          DECL_ALIGN (decl) = TYPE_ALIGN (vectype);
-          DECL_USER_ALIGN (decl) = 1;
-         if (TREE_STATIC (decl))
-           {
-             tree target = symtab_node::get (decl)->ultimate_alias_target ()->decl;
-              DECL_ALIGN (target) = TYPE_ALIGN (vectype);
-              DECL_USER_ALIGN (target) = 1;
-           }
+         vnode->increase_alignment (TYPE_ALIGN (vectype));
           dump_printf (MSG_NOTE, "Increasing alignment of decl: ");
           dump_generic_expr (MSG_NOTE, TDF_SLIM, decl);
           dump_printf (MSG_NOTE, "\n");
index 8f93a51..4fcc272 100644 (file)
@@ -4470,7 +4470,8 @@ extern tree block_ultimate_origin (const_tree);
 extern tree get_binfo_at_offset (tree, HOST_WIDE_INT, tree);
 extern bool virtual_method_call_p (tree);
 extern tree obj_type_ref_class (tree ref);
-extern bool types_same_for_odr (const_tree type1, const_tree type2);
+extern bool types_same_for_odr (const_tree type1, const_tree type2,
+                               bool strict=false);
 extern bool contains_bitfld_component_ref_p (const_tree);
 extern bool type_in_anonymous_namespace_p (const_tree);
 extern bool block_may_fallthru (const_tree);
index 38d98cf..0e23d91 100644 (file)
@@ -864,6 +864,7 @@ ubsan_expand_null_ifn (gimple_stmt_iterator *gsip)
 
       /* Replace the UBSAN_NULL with a GIMPLE_COND stmt.  */
       gsi_replace (&gsi, g, false);
+      stmt = g;
     }
 
   if (check_align)
@@ -1022,11 +1023,16 @@ ubsan_expand_objsize_ifn (gimple_stmt_iterator *gsi)
 
       /* Point GSI to next logical statement.  */
       *gsi = gsi_start_bb (fallthru_bb);
+
+      /* Get rid of the UBSAN_OBJECT_SIZE call from the IR.  */
+      unlink_stmt_vdef (stmt);
+      gsi_remove (&gsi_orig, true);
+      return true;
     }
 
   /* Get rid of the UBSAN_OBJECT_SIZE call from the IR.  */
   unlink_stmt_vdef (stmt);
-  gsi_remove (&gsi_orig, true);
+  gsi_remove (gsi, true);
   return true;
 }
 
index 9ec5d8b..da4c61e 100644 (file)
@@ -1011,7 +1011,13 @@ use_narrower_mode (rtx x, machine_mode mode, machine_mode wmode)
       return simplify_gen_binary (GET_CODE (x), mode, op0, op1);
     case ASHIFT:
       op0 = use_narrower_mode (XEXP (x, 0), mode, wmode);
-      return simplify_gen_binary (ASHIFT, mode, op0, XEXP (x, 1));
+      op1 = XEXP (x, 1);
+      /* Ensure shift amount is not wider than mode.  */
+      if (GET_MODE (op1) == VOIDmode)
+       op1 = lowpart_subreg (mode, op1, wmode);
+      else if (GET_MODE_PRECISION (mode) < GET_MODE_PRECISION (GET_MODE (op1)))
+       op1 = lowpart_subreg (mode, op1, GET_MODE (op1));
+      return simplify_gen_binary (ASHIFT, mode, op0, op1);
     default:
       gcc_unreachable ();
     }
index 8173207..752dccf 100644 (file)
@@ -659,7 +659,7 @@ function_section_1 (tree decl, bool force_cold)
   else
     return targetm.asm_out.select_section
            (decl, freq == NODE_FREQUENCY_UNLIKELY_EXECUTED,
-            DECL_ALIGN (decl));
+            symtab_node::get (decl)->definition_alignment ());
 #else
   if (targetm.asm_out.function_section)
     section = targetm.asm_out.function_section (decl, freq, startup, exit);
@@ -1630,35 +1630,30 @@ default_ctor_section_asm_out_constructor (rtx symbol,
 void
 notice_global_symbol (tree decl)
 {
-  const char **type = &first_global_object_name;
+  const char **t = &first_global_object_name;
 
   if (first_global_object_name
       || !TREE_PUBLIC (decl)
       || DECL_EXTERNAL (decl)
       || !DECL_NAME (decl)
+      || (TREE_CODE (decl) == VAR_DECL && DECL_HARD_REGISTER (decl))
       || (TREE_CODE (decl) != FUNCTION_DECL
          && (TREE_CODE (decl) != VAR_DECL
              || (DECL_COMMON (decl)
                  && (DECL_INITIAL (decl) == 0
-                     || DECL_INITIAL (decl) == error_mark_node))))
-      || !MEM_P (DECL_RTL (decl)))
+                     || DECL_INITIAL (decl) == error_mark_node)))))
     return;
 
   /* We win when global object is found, but it is useful to know about weak
      symbol as well so we can produce nicer unique names.  */
   if (DECL_WEAK (decl) || DECL_ONE_ONLY (decl) || flag_shlib)
-    type = &weak_global_object_name;
+    t = &weak_global_object_name;
 
-  if (!*type)
+  if (!*t)
     {
-      const char *p;
-      const char *name;
-      rtx decl_rtl = DECL_RTL (decl);
-
-      p = targetm.strip_name_encoding (XSTR (XEXP (decl_rtl, 0), 0));
-      name = ggc_strdup (p);
-
-      *type = name;
+      tree id = DECL_ASSEMBLER_NAME (decl);
+      ultimate_transparent_alias_target (&id);
+      *t = ggc_strdup (targetm.strip_name_encoding (IDENTIFIER_POINTER (id)));
     }
 }
 
@@ -1740,6 +1735,8 @@ assemble_start_function (tree decl, const char *fnname)
   if (CONSTANT_POOL_BEFORE_FUNCTION)
     output_constant_pool (fnname, decl);
 
+  align = symtab_node::get (decl)->definition_alignment ();
+
   /* Make sure the not and cold text (code) sections are properly
      aligned.  This is necessary here in the case where the function
      has both hot and cold sections, because we don't want to re-set
@@ -1750,7 +1747,7 @@ assemble_start_function (tree decl, const char *fnname)
       first_function_block_is_cold = false;
 
       switch_to_section (unlikely_text_section ());
-      assemble_align (DECL_ALIGN (decl));
+      assemble_align (align);
       ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.cold_section_label);
 
       /* When the function starts with a cold section, we need to explicitly
@@ -1760,7 +1757,7 @@ assemble_start_function (tree decl, const char *fnname)
          && BB_PARTITION (ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb) == BB_COLD_PARTITION)
        {
          switch_to_section (text_section);
-         assemble_align (DECL_ALIGN (decl));
+         assemble_align (align);
          ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.hot_section_label);
          hot_label_written = true;
          first_function_block_is_cold = true;
@@ -1777,7 +1774,7 @@ assemble_start_function (tree decl, const char *fnname)
     ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.hot_section_label);
 
   /* Tell assembler to move to target machine's alignment for functions.  */
-  align = floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT);
+  align = floor_log2 (align / BITS_PER_UNIT);
   if (align > 0)
     {
       ASM_OUTPUT_ALIGN (asm_out_file, align);
@@ -1931,17 +1928,18 @@ assemble_string (const char *p, int size)
 /* A noswitch_section_callback for lcomm_section.  */
 
 static bool
-emit_local (tree decl ATTRIBUTE_UNUSED,
+emit_local (tree decl,
            const char *name ATTRIBUTE_UNUSED,
            unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
            unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
 {
+  int align = symtab_node::get (decl)->definition_alignment ();
 #if defined ASM_OUTPUT_ALIGNED_DECL_LOCAL
   ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name,
-                                size, DECL_ALIGN (decl));
+                                size, align);
   return true;
 #elif defined ASM_OUTPUT_ALIGNED_LOCAL
-  ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, DECL_ALIGN (decl));
+  ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, align);
   return true;
 #else
   ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
@@ -3295,7 +3293,12 @@ build_constant_desc (tree exp)
   /* Now construct the SYMBOL_REF and the MEM.  */
   if (use_object_blocks_p ())
     {
-      section *sect = get_constant_section (exp, DECL_ALIGN (decl));
+      int align = (TREE_CODE (decl) == CONST_DECL
+                  || (TREE_CODE (decl) == VAR_DECL
+                      && DECL_IN_CONSTANT_POOL (decl))
+                  ? DECL_ALIGN (decl)
+                  : symtab_node::get (decl)->definition_alignment ());
+      section *sect = get_constant_section (exp, align);
       symbol = create_block_symbol (ggc_strdup (label),
                                    get_block_for_section (sect), -1);
     }
@@ -3423,7 +3426,6 @@ output_constant_def_contents (rtx symbol)
 {
   tree decl = SYMBOL_REF_DECL (symbol);
   tree exp = DECL_INITIAL (decl);
-  unsigned int align;
   bool asan_protected = false;
 
   /* Make sure any other constants whose addresses appear in EXP
@@ -3449,7 +3451,11 @@ output_constant_def_contents (rtx symbol)
     place_block_symbol (symbol);
   else
     {
-      align = DECL_ALIGN (decl);
+      int align = (TREE_CODE (decl) == CONST_DECL
+                  || (TREE_CODE (decl) == VAR_DECL
+                      && DECL_IN_CONSTANT_POOL (decl))
+                  ? DECL_ALIGN (decl)
+                  : symtab_node::get (decl)->definition_alignment ());
       switch_to_section (get_constant_section (exp, align));
       if (align > BITS_PER_UNIT)
        ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
@@ -7159,6 +7165,7 @@ place_block_symbol (rtx symbol)
   else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
     {
       decl = SYMBOL_REF_DECL (symbol);
+      gcc_checking_assert (DECL_IN_CONSTANT_POOL (decl));
       alignment = DECL_ALIGN (decl);
       size = get_constant_size (DECL_INITIAL (decl));
       if ((flag_sanitize & SANITIZE_ADDRESS)
@@ -7333,8 +7340,9 @@ output_object_block (struct object_block *block)
        {
          HOST_WIDE_INT size;
          decl = SYMBOL_REF_DECL (symbol);
-         assemble_constant_contents (DECL_INITIAL (decl), XSTR (symbol, 0),
-                                     DECL_ALIGN (decl));
+         assemble_constant_contents
+              (DECL_INITIAL (decl), XSTR (symbol, 0), DECL_ALIGN (decl));
+
          size = get_constant_size (DECL_INITIAL (decl));
          offset += size;
          if ((flag_sanitize & SANITIZE_ADDRESS)
index 707f62f..ce64279 100644 (file)
@@ -173,7 +173,7 @@ varpool_node::get_create (tree decl)
   node = varpool_node::create_empty ();
   node->decl = decl;
 
-  if ((flag_openacc || flag_openmp)
+  if ((flag_openacc || flag_openmp) && !DECL_EXTERNAL (decl)
       && lookup_attribute ("omp declare target", DECL_ATTRIBUTES (decl)))
     {
       node->offloadable = 1;
@@ -195,6 +195,11 @@ void
 varpool_node::remove (void)
 {
   symtab->call_varpool_removal_hooks (this);
+  if (lto_file_data)
+    {
+      lto_free_function_in_decl_state_for_node (this);
+      lto_file_data = NULL;
+    }
 
   /* When streaming we can have multiple nodes associated with decl.  */
   if (symtab->state == LTO_STREAMING)
@@ -323,6 +328,7 @@ varpool_node::get_constructor (void)
                 name);
 
   lto_input_variable_constructor (file_data, this, data);
+  gcc_assert (DECL_INITIAL (decl) != error_mark_node);
   lto_stats.num_function_bodies++;
   lto_free_section_data (file_data, LTO_section_function_body, name,
                         data, len);
index 2b09da6..a23c2c9 100644 (file)
@@ -1483,17 +1483,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 
   // [7.10] Class template match_results
 
-  /*
-   * Special sub_match object representing an unmatched sub-expression.
-   */
-  template<typename _Bi_iter>
-    inline const sub_match<_Bi_iter>&
-    __unmatched_sub()
-    {
-      static const sub_match<_Bi_iter> __unmatched = sub_match<_Bi_iter>();
-      return __unmatched;
-    }
-
   /**
    * @brief The results of a match or search operation.
    *
@@ -1523,15 +1512,20 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     {
     private:
       /*
-       * The vector base is empty if this does not represent a successful match.
-       * Otherwise it contains n+3 elements where n is the number of marked
+       * The vector base is empty if this does not represent a match (!ready());
+       * Otherwise if it's a match failure, it contains 3 elements:
+       * [0] unmatched
+       * [1] prefix
+       * [2] suffix
+       * Otherwise it contains n+4 elements where n is the number of marked
        * sub-expressions:
        * [0] entire match
        * [1] 1st marked subexpression
        * ...
        * [n] nth marked subexpression
-       * [n+1] prefix
-       * [n+2] suffix
+       * [n+1] unmatched
+       * [n+2] prefix
+       * [n+3] suffix
        */
       typedef std::vector<sub_match<_Bi_iter>, _Alloc>     _Base_type;
       typedef std::iterator_traits<_Bi_iter>                      __iter_traits;
@@ -1623,10 +1617,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
        */
       size_type
       size() const
-      {
-       size_type __size = _Base_type::size();
-       return (__size && _Base_type::operator[](0).matched) ? __size - 2 : 0;
-      }
+      { return _Base_type::empty() ? 0 : _Base_type::size() - 3; }
 
       size_type
       max_size() const
@@ -1670,15 +1661,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
        * is zero (the default), in which case this function returns the offset
        * from the beginning of the target sequence to the beginning of the
        * match.
-       *
-       * Returns -1 if @p __sub is out of range.
        */
       difference_type
       position(size_type __sub = 0) const
-      {
-       return __sub < size() ? std::distance(_M_begin,
-                                             (*this)[__sub].first) : -1;
-      }
+      { return std::distance(_M_begin, (*this)[__sub].first); }
 
       /**
        * @brief Gets the match or submatch converted to a string type.
@@ -1691,7 +1677,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
        */
       string_type
       str(size_type __sub = 0) const
-      { return (*this)[__sub].str(); }
+      { return string_type((*this)[__sub]); }
 
       /**
        * @brief Gets a %sub_match reference for the match or submatch.
@@ -1707,10 +1693,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       const_reference
       operator[](size_type __sub) const
       {
-       _GLIBCXX_DEBUG_ASSERT( ready() );
-       return __sub < size()
-              ?  _Base_type::operator[](__sub)
-              : __unmatched_sub<_Bi_iter>();
+       _GLIBCXX_DEBUG_ASSERT( ready() );
+       return __sub < size()
+              ? _Base_type::operator[](__sub)
+              : _M_unmatched_sub();
       }
 
       /**
@@ -1724,10 +1710,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       const_reference
       prefix() const
       {
-       _GLIBCXX_DEBUG_ASSERT( ready() );
-       return !empty()
-              ? _Base_type::operator[](_Base_type::size() - 2)
-              : __unmatched_sub<_Bi_iter>();
+       _GLIBCXX_DEBUG_ASSERT( ready() );
+       return !empty() ? _M_prefix() : _M_unmatched_sub();
       }
 
       /**
@@ -1742,9 +1726,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       suffix() const
       {
        _GLIBCXX_DEBUG_ASSERT( ready() );
-       return !empty()
-              ? _Base_type::operator[](_Base_type::size() - 1)
-              : __unmatched_sub<_Bi_iter>();
+       return !empty() ? _M_suffix() : _M_unmatched_sub();
       }
 
       /**
@@ -1766,7 +1748,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
        */
       const_iterator
       end() const
-      { return _Base_type::end() - 2; }
+      { return _Base_type::end() - 3; }
 
       /**
        * @brief Gets an iterator to one-past-the-end of the collection.
@@ -1883,6 +1865,34 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
                                    const basic_regex<_Cp, _Rp>&,
                                    regex_constants::match_flag_type);
 
+      void
+      _M_resize(unsigned int __size)
+      { _Base_type::resize(__size + 3); }
+
+      const_reference
+      _M_unmatched_sub() const
+      { return _Base_type::operator[](_Base_type::size() - 3); }
+
+      sub_match<_Bi_iter>&
+      _M_unmatched_sub()
+      { return _Base_type::operator[](_Base_type::size() - 3); }
+
+      const_reference
+      _M_prefix() const
+      { return _Base_type::operator[](_Base_type::size() - 2); }
+
+      sub_match<_Bi_iter>&
+      _M_prefix()
+      { return _Base_type::operator[](_Base_type::size() - 2); }
+
+      const_reference
+      _M_suffix() const
+      { return _Base_type::operator[](_Base_type::size() - 1); }
+
+      sub_match<_Bi_iter>&
+      _M_suffix()
+      { return _Base_type::operator[](_Base_type::size() - 1); }
+
       _Bi_iter _M_begin;
     };
 
index aad56e0..823ad51 100644 (file)
@@ -63,7 +63,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       typename match_results<_BiIter, _Alloc>::_Base_type& __res = __m;
       __m._M_begin = __s;
-      __res.resize(__re._M_automaton->_M_sub_count() + 2);
+      __m._M_resize(__re._M_automaton->_M_sub_count());
       for (auto& __it : __res)
        __it.matched = false;
 
@@ -99,8 +99,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          for (auto& __it : __res)
            if (!__it.matched)
              __it.first = __it.second = __e;
-         auto& __pre = __res[__res.size()-2];
-         auto& __suf = __res[__res.size()-1];
+         auto& __pre = __m._M_prefix();
+         auto& __suf = __m._M_suffix();
          if (__match_mode)
            {
              __pre.matched = false;
@@ -120,6 +120,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
              __suf.matched = (__suf.first != __suf.second);
            }
        }
+      else
+       {
+         __m._M_resize(0);
+         for (auto& __it : __res)
+           {
+             __it.matched = false;
+             __it.first = __it.second = __e;
+           }
+       }
       return __ret;
     }
 
@@ -374,7 +383,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       auto __output = [&](size_t __idx)
        {
-         auto& __sub = _Base_type::operator[](__idx);
+         auto& __sub = (*this)[__idx];
          if (__sub.matched)
            __out = std::copy(__sub.first, __sub.second, __out);
        };
@@ -425,9 +434,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
              else if (__eat('&'))
                __output(0);
              else if (__eat('`'))
-               __output(_Base_type::size()-2);
+               {
+                 auto& __sub = _M_prefix();
+                 if (__sub.matched)
+                   __out = std::copy(__sub.first, __sub.second, __out);
+               }
              else if (__eat('\''))
-               __output(_Base_type::size()-1);
+               {
+                 auto& __sub = _M_suffix();
+                 if (__sub.matched)
+                   __out = std::copy(__sub.first, __sub.second, __out);
+               }
              else if (__fctyp.is(__ctype_type::digit, *__next))
                {
                  long __num = __traits.value(*__next, 10);
@@ -532,7 +549,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                                   | regex_constants::match_continuous))
                    {
                      _GLIBCXX_DEBUG_ASSERT(_M_match[0].matched);
-                     auto& __prefix = _M_match.at(_M_match.size());
+                     auto& __prefix = _M_match._M_prefix();
                      __prefix.first = __prefix_first;
                      __prefix.matched = __prefix.first != __prefix.second;
                      // [28.12.1.4.5]
@@ -547,7 +564,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          if (regex_search(__start, _M_end, _M_match, *_M_pregex, _M_flags))
            {
              _GLIBCXX_DEBUG_ASSERT(_M_match[0].matched);
-             auto& __prefix = _M_match.at(_M_match.size());
+             auto& __prefix = _M_match._M_prefix();
              __prefix.first = __prefix_first;
              __prefix.matched = __prefix.first != __prefix.second;
              // [28.12.1.4.5]
index 5c49ac7..ba3f8be 100644 (file)
@@ -31,7 +31,7 @@
 //
 
 #ifndef _GLIBCXX_EXPERIMENTAL_SYSTEM_ERROR
-#define _GLIBCXX_EXPERIMENTAL_CHRONO 1
+#define _GLIBCXX_EXPERIMENTAL_SYSTEM_ERROR 1
 
 #pragma GCC system_header