Hi, this PR is about odd inconsistencies about comdat variables being or not being optimized out at -O0 with LTO. This is a side effect of the logic where COMDAT variables are output on demand at -O0, while static variables are output always. This logic is here from pre-cgraph times where we did not optimized out unused static vars in C at all, but we did, sort-of, optimized out unused comdats in C++ FE.
Some tools depends on strings stored into unused static vars to survive and it probably makes sense to behave this way at -O0. Now this all becomes bit incosistent when LTO brings COMDAT vars private with LTO even at -O0. This patch moves this handling earlier. At a time we finalize decl we check toplevel_reorder and in !toplevel_reorder we mark all non-COMDAT non-artifical variables as forced to output Rest of compiler now can work same was at -O0 or not. This is cleaner and more consistent. Richi, does this fix all issues you saw? It seems to work on the testcase provided, but I know it comes from some more involved analysis. Do we want to avoid privatization of symbols with LTO at -O0? It probably makes sense to do so as the privatization breaks debugging. What about -fwhole-program? In this case I would lean towards still honoring it since user has to explicitely ask for it. Bootstrapped/regtested x86_64-linux, comitted. Honza PR lto/51663 * varpool.c (varpool_finalize_decl): Handle toplevel_reorder here. (decide_is_variable_needed): Do not handle toplevel reorder here. * cgraph.h (varpool_can_remove_if_no_refs): Likewise. * ipa.c (cgraph_remove_unreachable_nodes): Remove unreachable vars even at -O0. Index: cgraph.h =================================================================== --- cgraph.h (revision 185774) +++ cgraph.h (working copy) @@ -947,8 +947,6 @@ static inline bool varpool_can_remove_if_no_refs (struct varpool_node *node) { return (!node->force_output && !node->used_from_other_partition - && (flag_toplevel_reorder || DECL_COMDAT (node->decl) - || DECL_ARTIFICIAL (node->decl)) && (DECL_COMDAT (node->decl) || !node->externally_visible)); } Index: ipa.c =================================================================== --- ipa.c (revision 185774) +++ ipa.c (working copy) @@ -419,11 +419,6 @@ cgraph_remove_unreachable_nodes (bool be if (file) fprintf (file, "\n"); - /* We must release unused extern inlines or sanity checking will fail. Rest of transformations - are undesirable at -O0 since we do not want to remove anything. */ - if (!optimize) - return changed; - if (file) fprintf (file, "Reclaiming variables:"); for (vnode = varpool_nodes; vnode; vnode = vnext) @@ -463,6 +458,10 @@ cgraph_remove_unreachable_nodes (bool be if (file) fprintf (file, "\n"); + /* Rest of transformations are undesirable at -O0. */ + if (!optimize) + return changed; + #ifdef ENABLE_CHECKING verify_cgraph (); #endif Index: varpool.c =================================================================== --- varpool.c (revision 185774) +++ varpool.c (working copy) @@ -334,10 +334,6 @@ decide_is_variable_needed (struct varpoo && !DECL_EXTERNAL (decl)) return true; - /* When not reordering top level variables, we have to assume that - we are going to keep everything. */ - if (!flag_toplevel_reorder) - return true; return false; } @@ -405,7 +401,11 @@ varpool_finalize_decl (tree decl) if (node->needed) varpool_enqueue_needed_node (node); node->finalized = true; - if (TREE_THIS_VOLATILE (decl) || DECL_PRESERVE_P (decl)) + if (TREE_THIS_VOLATILE (decl) || DECL_PRESERVE_P (decl) + /* Traditionally we do not eliminate static variables when not + optimizing and when not doing toplevel reoder. */ + || (!flag_toplevel_reorder && !DECL_COMDAT (node->decl) + && !DECL_ARTIFICIAL (node->decl))) node->force_output = true; if (decide_is_variable_needed (node, decl))