From 6b9ac1796ec8eed79e8d5e4ef03a347a6c86a25c Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Wed, 9 Dec 2015 03:15:05 +0100 Subject: [PATCH] re PR lto/61886 (LTO breaks fread with _FORTIFY_SOURCE=2) PR ipa/61886 * lto-streamer.h (lto_symtab_merge_decls, lto_symtab_merge_symbols, lto_symtab_prevailing_decl): MOve to lto-symtab.h. * lto-streamer-out.c (DFS::DFS_write_tree_body): Check that DECL_ABSTRACT_ORIGIN is not error_mark_node. * lto-symtab.c: Include lto-symtab.h. (lto_cgraph_replace_node): Do not merge profiles here. (lto_symtab_merge_p): New function. (lto_symtab_merge_decls_2): Honor lto_symtab_merge_p. (lto_symtab_merge_symbols_1): Turn unmerged decls into transparent aliases. (lto_symtab_merge_symbols): Do not clear node->aux; we no longer use it. (lto_symtab_prevailing_decl): Move to lto-symtab.h; rewrite. * lto.c: Include lto-symtab.h * lto-symtab.h: New. From-SVN: r231438 --- gcc/ChangeLog | 8 ++ gcc/lto-streamer-out.c | 6 +- gcc/lto-streamer.h | 5 -- gcc/lto/ChangeLog | 14 ++++ gcc/lto/lto-symtab.c | 180 ++++++++++++++++++++++++++++------------- gcc/lto/lto-symtab.h | 47 +++++++++++ gcc/lto/lto.c | 1 + 7 files changed, 197 insertions(+), 64 deletions(-) create mode 100644 gcc/lto/lto-symtab.h diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 26e63ca1966..44eddde4b11 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2015-12-08 Jan Hubicka + + PR ipa/61886 + * lto-streamer.h (lto_symtab_merge_decls, lto_symtab_merge_symbols, + lto_symtab_prevailing_decl): MOve to lto-symtab.h. + * lto-streamer-out.c (DFS::DFS_write_tree_body): Check that + DECL_ABSTRACT_ORIGIN is not error_mark_node. + 2015-12-08 David Malcolm * tree-nested.c (convert_tramp_reference_stmt): Fix indentation. diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c index 8928873bcc2..a8748464c21 100644 --- a/gcc/lto-streamer-out.c +++ b/gcc/lto-streamer-out.c @@ -731,7 +731,11 @@ DFS::DFS_write_tree_body (struct output_block *ob, /* Do not follow DECL_ABSTRACT_ORIGIN. We cannot handle debug information for early inlining so drop it on the floor instead of ICEing in - dwarf2out.c. */ + dwarf2out.c. + We however use DECL_ABSTRACT_ORIGIN == error_mark_node to mark + declarations which should be eliminated by decl merging. Be sure none + leaks to this point. */ + gcc_assert (DECL_ABSTRACT_ORIGIN (expr) != error_mark_node); if ((TREE_CODE (expr) == VAR_DECL || TREE_CODE (expr) == PARM_DECL) diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h index 5aae9e9bfa7..99f88b89f9d 100644 --- a/gcc/lto-streamer.h +++ b/gcc/lto-streamer.h @@ -927,11 +927,6 @@ void cl_optimization_stream_out (struct bitpack_d *, struct cl_optimization *); void cl_optimization_stream_in (struct bitpack_d *, struct cl_optimization *); -/* In lto-symtab.c. */ -extern void lto_symtab_merge_decls (void); -extern void lto_symtab_merge_symbols (void); -extern tree lto_symtab_prevailing_decl (tree decl); - /* In lto-opts.c. */ extern void lto_write_options (void); diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index 5fba06a21f2..faeb3eedc70 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,17 @@ +2015-12-08 Jan Hubicka + + PR ipa/61886 + * lto-symtab.c: Include lto-symtab.h. + (lto_cgraph_replace_node): Do not merge profiles here. + (lto_symtab_merge_p): New function. + (lto_symtab_merge_decls_2): Honor lto_symtab_merge_p. + (lto_symtab_merge_symbols_1): Turn unmerged decls into transparent + aliases. + (lto_symtab_merge_symbols): Do not clear node->aux; we no longer use it. + (lto_symtab_prevailing_decl): Move to lto-symtab.h; rewrite. + * lto.c: Include lto-symtab.h + * lto-symtab.h: New. + 2015-12-08 Jan Hubicka PR ipa/61886 diff --git a/gcc/lto/lto-symtab.c b/gcc/lto/lto-symtab.c index e5055b593a8..a0cc1708d74 100644 --- a/gcc/lto/lto-symtab.c +++ b/gcc/lto/lto-symtab.c @@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see #include "ipa-utils.h" #include "builtins.h" #include "alias.h" +#include "lto-symtab.h" /* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging all edges and removing the old node. */ @@ -99,7 +100,6 @@ lto_cgraph_replace_node (struct cgraph_node *node, node->instrumented_version = NULL; } - ipa_merge_profiles (prevailing_node, node); lto_free_function_in_decl_state_for_node (node); if (node->decl != prevailing_node->decl) @@ -503,6 +503,30 @@ lto_symtab_resolve_symbols (symtab_node *first) return prevailing; } +/* Decide if it is OK to merge DECL into PREVAILING. + Because we wrap most of uses of declarations in MEM_REF, we can tolerate + some differences but other code may inspect directly the DECL. */ + +static bool +lto_symtab_merge_p (tree prevailing, tree decl) +{ + if (TREE_CODE (prevailing) != TREE_CODE (decl)) + return false; + if (TREE_CODE (prevailing) == FUNCTION_DECL) + { + if (DECL_BUILT_IN (prevailing) != DECL_BUILT_IN (decl)) + return false; + if (DECL_BUILT_IN (prevailing) + && (DECL_BUILT_IN_CLASS (prevailing) != DECL_BUILT_IN_CLASS (decl) + || DECL_FUNCTION_CODE (prevailing) != DECL_FUNCTION_CODE (decl))) + return false; + } + /* There are several other cases where merging can not be done, but until + aliasing code is fixed to support aliases it we can not really return + false on non-readonly var, yet. */ + return true; +} + /* Merge all decls in the symbol table chain to the prevailing decl and issue diagnostics about type mismatches. If DIAGNOSED_P is true do not issue further diagnostics.*/ @@ -523,15 +547,59 @@ lto_symtab_merge_decls_2 (symtab_node *first, bool diagnosed_p) return; /* Try to merge each entry with the prevailing one. */ - for (e = prevailing->next_sharing_asm_name; - e; e = e->next_sharing_asm_name) - if (TREE_PUBLIC (e->decl)) - { - if (!lto_symtab_merge (prevailing, e) - && !diagnosed_p - && !DECL_ARTIFICIAL (e->decl)) - mismatches.safe_push (e->decl); - } + symtab_node *last_prevailing = prevailing, *next; + for (e = prevailing->next_sharing_asm_name; e; e = next) + { + next = e->next_sharing_asm_name; + + /* Skip non-LTO symbols and symbols whose declaration we already + visited. */ + if (lto_symtab_prevailing_decl (e->decl) != e->decl + || !lto_symtab_symbol_p (e) + || e->decl == prevailing->decl) + continue; + + if (!lto_symtab_merge (prevailing, e) + && !diagnosed_p + && !DECL_ARTIFICIAL (e->decl)) + mismatches.safe_push (e->decl); + + symtab_node *this_prevailing; + for (this_prevailing = prevailing; ; + this_prevailing = this_prevailing->next_sharing_asm_name) + { + if (lto_symtab_merge_p (this_prevailing->decl, e->decl)) + break; + if (this_prevailing == last_prevailing) + { + this_prevailing = NULL; + break; + } + } + + if (this_prevailing) + lto_symtab_prevail_decl (this_prevailing->decl, e->decl); + /* Maintain LRU list: relink the new prevaililng symbol + just after previaling node in the chain and update last_prevailing. + Since the number of possible declarations of a given symbol is + small, this should be faster than building a hash. */ + else if (e == prevailing->next_sharing_asm_name) + last_prevailing = e; + else + { + if (e->next_sharing_asm_name) + e->next_sharing_asm_name->previous_sharing_asm_name + = e->previous_sharing_asm_name; + e->previous_sharing_asm_name->next_sharing_asm_name + = e->next_sharing_asm_name; + e->previous_sharing_asm_name = prevailing; + e->next_sharing_asm_name = prevailing->next_sharing_asm_name; + prevailing->next_sharing_asm_name->previous_sharing_asm_name = e; + prevailing->next_sharing_asm_name = e; + if (last_prevailing == prevailing) + last_prevailing = e; + } + } if (mismatches.is_empty ()) return; @@ -729,6 +797,8 @@ lto_symtab_merge_symbols_1 (symtab_node *prevailing) symtab_node *e; symtab_node *next; + prevailing->decl->decl_with_vis.symtab_node = prevailing; + /* Replace the cgraph node of each entry with the prevailing one. */ for (e = prevailing->next_sharing_asm_name; e; e = next) @@ -738,10 +808,47 @@ lto_symtab_merge_symbols_1 (symtab_node *prevailing) if (!lto_symtab_symbol_p (e)) continue; cgraph_node *ce = dyn_cast (e); - if (ce && !DECL_BUILT_IN (e->decl)) - lto_cgraph_replace_node (ce, dyn_cast (prevailing)); - if (varpool_node *ve = dyn_cast (e)) - lto_varpool_replace_node (ve, dyn_cast (prevailing)); + symtab_node *to = symtab_node::get (lto_symtab_prevailing_decl (e->decl)); + + /* No matter how we are going to deal with resolution, we will ultimately + use prevailing definition. */ + if (ce) + ipa_merge_profiles (dyn_cast (prevailing), + dyn_cast (e)); + + /* If we decided to replace the node by TO, do it. */ + if (e != to) + { + if (ce) + lto_cgraph_replace_node (ce, dyn_cast (to)); + else if (varpool_node *ve = dyn_cast (e)) + lto_varpool_replace_node (ve, dyn_cast (to)); + } + /* Watch out for duplicated symbols for a given declaration. */ + else if (!e->transparent_alias + || !e->definition || e->get_alias_target () != to) + { + /* We got a new declaration we do not want to merge. In this case + get rid of the existing definition and create a transparent + alias. */ + if (ce) + { + lto_free_function_in_decl_state_for_node (ce); + if (!ce->weakref) + ce->release_body (); + ce->reset (); + symtab->call_cgraph_removal_hooks (ce); + } + else + { + DECL_INITIAL (e->decl) = error_mark_node; + symtab->call_varpool_removal_hooks (dyn_cast (e)); + } + e->remove_all_references (); + e->analyzed = e->body_removed = false; + e->resolve_alias (prevailing, true); + gcc_assert (e != prevailing); + } } return; @@ -782,9 +889,8 @@ lto_symtab_merge_symbols (void) symtab_node *tgt = symtab_node::get_for_asmname (node->alias_target); gcc_assert (node->weakref); if (tgt) - node->resolve_alias (tgt); + node->resolve_alias (tgt, true); } - node->aux = NULL; if (!(cnode = dyn_cast (node)) || !cnode->clone_of @@ -821,45 +927,3 @@ lto_symtab_merge_symbols (void) } } } - -/* Given the decl DECL, return the prevailing decl with the same name. */ - -tree -lto_symtab_prevailing_decl (tree decl) -{ - symtab_node *ret; - - /* Builtins and local symbols are their own prevailing decl. */ - if ((!TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl)) || is_builtin_fn (decl)) - return decl; - - /* DECL_ABSTRACT_Ps are their own prevailing decl. */ - if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT_P (decl)) - return decl; - - /* When decl did not participate in symbol resolution leave it alone. - This can happen when we streamed the decl as abstract origin - from the block tree of inlining a partially inlined function. - If all, the split function and the original function end up - optimized away early we do not put the abstract origin into the - ltrans boundary and we'll end up ICEing in - dwarf2out.c:gen_inlined_subroutine_die because we eventually - replace a decl with DECL_POSSIBLY_INLINED set with one without. */ - if (TREE_CODE (decl) == FUNCTION_DECL - && ! cgraph_node::get (decl)) - return decl; - - /* Ensure DECL_ASSEMBLER_NAME will not set assembler name. */ - gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl)); - - /* Walk through the list of candidates and return the one we merged to. */ - ret = symtab_node::get_for_asmname (DECL_ASSEMBLER_NAME (decl)); - if (!ret) - return decl; - - /* Do not replace a non-builtin with a builtin. */ - if (is_builtin_fn (ret->decl)) - return decl; - - return ret->decl; -} diff --git a/gcc/lto/lto-symtab.h b/gcc/lto/lto-symtab.h new file mode 100644 index 00000000000..c6b68b6001e --- /dev/null +++ b/gcc/lto/lto-symtab.h @@ -0,0 +1,47 @@ +/* LTO symbol table merging. + Copyright (C) 2009-2015 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +extern void lto_symtab_merge_decls (void); +extern void lto_symtab_merge_symbols (void); +extern tree lto_symtab_prevailing_decl (tree decl); + +/* Mark DECL to be previailed by PREVAILING. + Use DECL_ABSTRACT_ORIGIN and DECL_CHAIN as special markers; those do not + disturb debug_tree and diagnostics. + We are safe to modify them as we wish, becuase the declarations disappear + from the IL after the merging. */ + +inline void +lto_symtab_prevail_decl (tree prevailing, tree decl) +{ + gcc_checking_assert (DECL_ABSTRACT_ORIGIN (decl) != error_mark_node); + DECL_CHAIN (decl) = prevailing; + DECL_ABSTRACT_ORIGIN (decl) = error_mark_node; +} + +/* Given the decl DECL, return the prevailing decl with the same name. */ + +inline tree +lto_symtab_prevailing_decl (tree decl) +{ + if (DECL_ABSTRACT_ORIGIN (decl) == error_mark_node) + return DECL_CHAIN (decl); + else + return decl; +} diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c index dcfa3c868f3..90712b45ecb 100644 --- a/gcc/lto/lto.c +++ b/gcc/lto/lto.c @@ -49,6 +49,7 @@ along with GCC; see the file COPYING3. If not see #include "params.h" #include "ipa-utils.h" #include "gomp-constants.h" +#include "lto-symtab.h" /* Number of parallel tasks to run, -1 if we want to use GNU Make jobserver. */