From patchwork Wed Jul 12 15:42:24 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?RnJhbmtsaW4g4oCcU25haXBl4oCdIE1hdGhpZXU=?= X-Patchwork-Id: 787319 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3x73BG3tMLz9ryQ for ; Thu, 13 Jul 2017 01:43:02 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="WqBk2Xl7"; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; q=dns; s= default; b=Y9mzXEzy0VwVOXvJjHBj0COdNaaqtNhljG3R7QMAyBsC2jZC0w2rU 5SEEYW8SlRGE1D/sPt2vplKeUY7A8j36JEkIcgMH74n2fBLkg9vIJIVGyBbUiv+O v4UCxgkO4Kfeg3+xXhphYfFOB0Okw1Mz4uYdiacZo5OQaA6sd3W9Ck= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; s=default; bh=v4sKc0T0NDJ3g9f6cSJbydmzjxc=; b=WqBk2Xl7/C7aYXULIuYTo7iM//AP peMPeLX+VfcjNcXICX/xBy5wAuQhP8WyDWI7qcJzE3f7MBVLC6YVm3xUqos1aJ+U /hKq7UMtHm2hGFiHrLcbNelTxwK4KKtunUrXvEDYtbnpd5lsf2sE2JJv16F50U6U Dh5xiAW4lNkMyD4= Received: (qmail 86204 invoked by alias); 12 Jul 2017 15:42:40 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 86123 invoked by uid 89); 12 Jul 2017 15:42:39 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.8 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, RCVD_IN_SORBS_SPAM, SPF_PASS autolearn=ham version=3.3.2 spammy=H*Ad:D*io, networks, Networks X-HELO: mail-lf0-f50.google.com Received: from mail-lf0-f50.google.com (HELO mail-lf0-f50.google.com) (209.85.215.50) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 12 Jul 2017 15:42:36 +0000 Received: by mail-lf0-f50.google.com with SMTP id b207so20758511lfg.2 for ; Wed, 12 Jul 2017 08:42:35 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=/+3cvvUpo7n30GeGDQgZMhMmFjbGzday78tv6y4BqiU=; b=WMxSA2Bjh/m002zfJVImmb+si2+WeBQQD+ZjYMo8eeTIxzfXWd7xJiRHRPuEXleQrD fAGHyi0ez5FTsJGhgRENYetd4AjwVd7NFUxXayNMtUu0LdMD8bNufEYymI4Lblp9I5wk CjgOL7LZQy++iBmnHMRQcQR8gVvkh364sIEH3R29wy7x2Il675x+bEtD31ZhUCLptQet HLC6on/3CnTg2fsIqXObJfGSYBpiYiO8cLg2EJ7KCCbWZMNmUYTENmKlU9gtYkQcMgjC dJAOVXJaN2fMEBb2eYP1h2A6PEF91mMDz/HiBoXGuEqj/EVcuh72M1lEJx8w8Ah81gAu 6oWA== X-Gm-Message-State: AIVw112vwpjPGS3KxpOV1GcX8l+ZxkRnew6hPZw8sG0g3qZlc0JwwEDO 3Fl5q7ezz5zITQHzYdvQCg== X-Received: by 10.80.221.7 with SMTP id t7mr6619314edk.134.1499874153578; Wed, 12 Jul 2017 08:42:33 -0700 (PDT) Received: from snaipe-arista.ire.aristanetworks.com ([217.173.96.166]) by smtp.gmail.com with ESMTPSA id h58sm1541841edh.52.2017.07.12.08.42.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 12 Jul 2017 08:42:33 -0700 (PDT) From: =?UTF-8?q?Franklin=20=E2=80=9CSnaipe=E2=80=9D=20Mathieu?= To: gcc-patches@gcc.gnu.org Cc: snaipe@arista.com, =?UTF-8?q?Franklin=20=E2=80=9CSnaipe=E2=80=9D=20Mathieu?= Subject: [PATCH v1 1/3] dwarf: purge DIEs for unreferenced extern globals. Date: Wed, 12 Jul 2017 16:42:24 +0100 Message-Id: <20170712154226.25508-2-snaipe@arista.com> In-Reply-To: <20170712154226.25508-1-snaipe@arista.com> References: <20170712154226.25508-1-snaipe@arista.com> MIME-Version: 1.0 From: Franklin “Snaipe” Mathieu Due to an earlier change in gcc that split the dwarf info generation in two steps (one early, one late), the DIE for unreferenced extern globals are no longer removed (in fact, they didn't emit it at all since they had already processed the translation unit and knew whether or not a variable was referenced). This is no longer the case during the early generation. This change addresses this problem by revisiting during the late stage global declarations on the C side, and for each namespace on the C++ side, removing DIEs when they are unreferenced in both cases. gcc/c/ChangeLog: 2017-07-12 Franklin “Snaipe” Mathieu PR debug/81135 * c-decl.c (c_parse_final_cleanups): Call the late_global_decl hook for each global in the extern block. gcc/cp/ChangeLog: 2017-07-12 Franklin “Snaipe” Mathieu PR debug/81135 * decl2.c (c_parse_final_cleanups): Call the late_global_decl for each extern variable in each namespace. (purge_unused_extern_globals): New. gcc/ChangeLog: 2017-07-12 Franklin “Snaipe” Mathieu PR debug/81135 * dwarf2out: Remove DIEs for unreferenced externs. (struct die_struct): Add removed field. (lookup_decl_die): Remove DIEs marked for removal. (mark_removed): New. (dwarf2out_late_global_decl): Refactor to remove DIE from the sibling list, and actually check that the code filling new new location information acts on the same conditions as it had when it was called from the symtab code. (dwarf2out_imported_module_or_decl_1): make the referenced DIE perennial to avoid it being removed when deemed unused, as it would be referenced by a DW_TAG_imported_declaration entry. gcc/testsuite/ChangeLog: 2017-07-12 Franklin “Snaipe” Mathieu PR debug/81135 gcc.dg/debug/dwarf2/pr81135.c: New test. g++.dg/debug/dwarf2/pr81135.C: New test. --- gcc/c/c-decl.c | 10 +++ gcc/cp/decl2.c | 41 +++++++++++ gcc/dwarf2out.c | 109 ++++++++++++++++++++-------- gcc/testsuite/g++.dg/debug/dwarf2/pr81135.C | 25 +++++++ gcc/testsuite/gcc.dg/debug/dwarf2/pr81135.C | 13 ++++ 5 files changed, 168 insertions(+), 30 deletions(-) create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/pr81135.C create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/pr81135.C diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 317d5cd..9d64046 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -11227,6 +11227,16 @@ c_parse_final_cleanups (void) c_write_global_declarations_1 (BLOCK_VARS (ext_block)); timevar_stop (TV_PHASE_DEFERRED); + + /* Purge unreferenced extern variables from the debug information. */ + if (!seen_error ()) + { + tree decl; + for (decl = BLOCK_VARS (ext_block); decl; decl = DECL_CHAIN (decl)) + if (DECL_EXTERNAL (decl)) + (*debug_hooks->late_global_decl) (decl); + } + timevar_start (TV_PHASE_PARSING); ext_block = NULL; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 877745c..93929e6 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see #include "calls.h" #include "decl.h" #include "toplev.h" +#include "debug.h" #include "c-family/c-objc.h" #include "c-family/c-pragma.h" #include "dumpfile.h" @@ -4408,6 +4409,42 @@ lower_var_init () } } +/* We call this routine on each namespace to remove unreferenced extern + variables from the debug information. */ + +static int +purge_unused_extern_globals (tree name_space) +{ + int rc; + cp_binding_level *level = NAMESPACE_LEVEL (name_space); + tree decl; + + if (seen_error ()) + return 1; + + if (!level) + return 0; + + for (decl = level->names; decl; decl = DECL_CHAIN (decl)) + { + switch (TREE_CODE (decl)) + { + case VAR_DECL: + if (DECL_EXTERNAL (decl)) + (*debug_hooks->late_global_decl) (decl); + break; + case NAMESPACE_DECL: + if ((rc = purge_unused_extern_globals (decl))) + return rc; + break; + default: + break; + } + } + + return 0; +} + /* This routine is called at the end of compilation. Its job is to create all the code needed to initialize and destroy the global aggregates. We do the destruction @@ -4791,6 +4828,10 @@ c_parse_final_cleanups (void) } timevar_stop (TV_PHASE_DEFERRED); + + /* Purge unreferenced extern variables from the debug information. */ + purge_unused_extern_globals (global_namespace); + timevar_start (TV_PHASE_PARSING); /* Indicate that we're done with front end processing. */ diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index c277d27..261aeef 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -62,6 +62,7 @@ along with GCC; see the file COPYING3. If not see #include "function.h" #include "rtl.h" #include "tree.h" +#include "cp/cp-tree.h" #include "memmodel.h" #include "tm_p.h" #include "stringpool.h" @@ -25512,6 +25513,16 @@ dwarf2out_early_global_decl (tree decl) symtab->global_info_ready = save; } +/* Mark DIE and its children as removed. */ + +static void +mark_removed (dw_die_ref die) +{ + dw_die_ref c; + die->removed = true; + FOR_EACH_CHILD (die, c, mark_removed (c)); +} + /* Output debug information for global decl DECL. Called from toplev.c after compilation proper has finished. */ @@ -25520,29 +25531,73 @@ dwarf2out_late_global_decl (tree decl) { /* Fill-in any location information we were unable to determine on the first pass. */ - if (VAR_P (decl) && !POINTER_BOUNDS_P (decl)) + if (! VAR_P (decl) || POINTER_BOUNDS_P (decl)) + return; + + dw_die_ref die = lookup_decl_die (decl); + + /* We have to generate early debug late for LTO. */ + if (! die && in_lto_p) { - dw_die_ref die = lookup_decl_die (decl); + dwarf2out_decl (decl); + die = lookup_decl_die (decl); + } - /* We have to generate early debug late for LTO. */ - if (! die && in_lto_p) - { - dwarf2out_decl (decl); - die = lookup_decl_die (decl); - } + /* Discard this VAR_DECL if it refers to a file-scope + (or namespace-scope) extern data object declaration and if the + declaration was never even referenced from within this entire + compilation unit. We suppress these DIEs in order to save space + in the .debug section (by eliminating entries which are probably + useless). Note that we must not suppress block-local extern and + static member declarations (whether used or not) because that + would screw-up the debugger's name lookup mechanism and cause + it to miss things which really ought to be in scope at a + given point. */ + if (die && ! die->die_perennial_p + && DECL_EXTERNAL (decl) + && ! DECL_CLASS_SCOPE_P (decl) + && ! TREE_USED (decl)) + { + mark_removed (die); - if (die) - { - /* We get called via the symtab code invoking late_global_decl - for symbols that are optimized out. Do not add locations - for those, except if they have a DECL_VALUE_EXPR, in which case - they are relevant for debuggers. */ - varpool_node *node = varpool_node::get (decl); - if ((! node || ! node->definition) && ! DECL_HAS_VALUE_EXPR_P (decl)) - tree_add_const_value_attribute_for_decl (die, decl); - else - add_location_or_const_value_attribute (die, decl, false); - } + dw_die_ref next = die->die_sib; + if (die == die->die_sib) + next = NULL; + + dw_die_ref *ptail = &die->die_parent->die_child; + dw_die_ref prev = (*ptail)->die_sib; + while (prev->die_sib != die) + prev = prev->die_sib; + prev->die_sib = next; + + if (prev == die) + prev = NULL; + if (*ptail == die) + *ptail = prev; + + die->die_parent = NULL; + die->die_sib = NULL; + + /* Die has been removed, so we pretend we couldn't find it in + the first place. */ + die = NULL; + } + + if (! die) + return; + + varpool_node *node = varpool_node::get (decl); + if ((! node || ! node->in_other_partition) + && ! DECL_EXTERNAL (decl)) + { + /* We get called via the symtab code invoking late_global_decl + for symbols that are optimized out. Do not add locations + for those, except if they have a DECL_VALUE_EXPR, in which case + they are relevant for debuggers. */ + if ((! node || ! node->definition) && ! DECL_HAS_VALUE_EXPR_P (decl)) + tree_add_const_value_attribute_for_decl (die, decl); + else + add_location_or_const_value_attribute (die, decl, false); } } @@ -25646,6 +25701,10 @@ dwarf2out_imported_module_or_decl_1 (tree decl, add_AT_string (imported_die, DW_AT_name, IDENTIFIER_POINTER (name)); add_AT_die_ref (imported_die, DW_AT_import, at_import_die); + + /* To avoid issues with the unreferenced extern removal, we mark the imported + DIE as perennial so it won't be considered for removal. */ + at_import_die->die_perennial_p = 1; } /* Output debug information for imported module or decl DECL. @@ -27860,16 +27919,6 @@ prune_unused_types_update_strings (dw_die_ref die) } } -/* Mark DIE and its children as removed. */ - -static void -mark_removed (dw_die_ref die) -{ - dw_die_ref c; - die->removed = true; - FOR_EACH_CHILD (die, c, mark_removed (c)); -} - /* Remove from the tree DIE any dies that aren't marked. */ static void diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/pr81135.C b/gcc/testsuite/g++.dg/debug/dwarf2/pr81135.C new file mode 100644 index 0000000..84cf557 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/pr81135.C @@ -0,0 +1,25 @@ +// { dg-do compile } +// { dg-options "-gdwarf-2 -dA" } +// { dg-final { scan-assembler "DW_TAG_variable\[^.\]*\.ascii \"i..\"" } } +// { dg-final { scan-assembler "DW_TAG_variable\[^.\]*\.ascii \"m..\"" } } +// { dg-final { scan-assembler-not "DW_TAG_variable\[^.\]*\.ascii \"j..\"" } } +// { dg-final { scan-assembler-not "DW_TAG_variable\[^.\]*\.ascii \"k..\"" } } +// { dg-final { scan-assembler-not "DW_TAG_variable\[^.\]*\.ascii \"l..\"" } } + +extern int i; +extern int j; + +namespace { + extern int k; +} + +namespace foo { + extern int l; + extern int m; +} + +int +main (void) +{ + return i + foo::m; +} diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/pr81135.C b/gcc/testsuite/gcc.dg/debug/dwarf2/pr81135.C new file mode 100644 index 0000000..5902bd3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/pr81135.C @@ -0,0 +1,13 @@ +// { dg-do compile } +// { dg-options "-gdwarf-2 -dA" } +// { dg-final { scan-assembler "DW_TAG_variable\[^.\]*\.ascii \"i..\"" } } +// { dg-final { scan-assembler-not "DW_TAG_variable\[^.\]*\.ascii \"j..\"" } } + +extern int i; +extern int j; + +int +main (void) +{ + return i; +}