From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 3290 invoked by alias); 18 Jan 2016 23:33:14 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 3277 invoked by uid 89); 18 Jan 2016 23:33:13 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD,SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=infos, PRO, 397, fcompare-debug X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Mon, 18 Jan 2016 23:33:12 +0000 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (Postfix) with ESMTPS id 06D53C09FAA8 for ; Mon, 18 Jan 2016 23:33:10 +0000 (UTC) Received: from tucnak.zalov.cz ([10.3.113.11]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u0INX9s7031872 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Mon, 18 Jan 2016 18:33:10 -0500 Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.15.2/8.15.2) with ESMTP id u0INX7SJ015547; Tue, 19 Jan 2016 00:33:08 +0100 Received: (from jakub@localhost) by tucnak.zalov.cz (8.15.2/8.15.2/Submit) id u0INX6ng015546; Tue, 19 Jan 2016 00:33:06 +0100 Date: Mon, 18 Jan 2016 23:33:00 -0000 From: Jakub Jelinek To: Bernd Schmidt , Jeff Law , Alexandre Oliva Cc: gcc-patches@gcc.gnu.org Subject: [PATCH] Fix debug info handling in prepare_shrink_wrap (PR debug/65779) Message-ID: <20160118233306.GE3017@tucnak.redhat.com> Reply-To: Jakub Jelinek MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.24 (2015-08-30) X-IsSubscribed: yes X-SW-Source: 2016-01/txt/msg01343.txt.bz2 Hi! On the following testcase with -mrelocatable on ppc32 we get assembly that contains undefined reference to a local .LC* symbol. The problem is that prepare_shrink_wrap attempts to schedule some instructions from the entry block to later basic blocks, if they set a register that is only used in one of the paths, but the debug infos are kept where they used to appear (that is correct thing to do), but nothing adjusts them or resets them); on most targets we get away just with wrong debug info, but on ppc32 -mrelocatable something in the prologue sets the hard registers used by some debug insns to subtraction of two magic labels, which are later removed as unneeded, but kept in the debug info. Fixed by using the infrastructure we have for this in valtrack.c, that is used by DCE and DF note problem computation. E.g. on ppc32, we used to have: (insn 34 38 35 2 (set (reg/v:SI 6 6 [orig:238 s1 ] [238]) (and:SI (reg/v:SI 3 3 [orig:264 adler ] [264]) (const_int 65535 [0xffff]))) ../../../../../../../../../rtems/c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/../../../powerpc/sha (nil)) (debug_insn 35 34 36 2 (var_location:SI s1 (reg/v:SI 6 6 [orig:238 s1 ] [238])) ../../../../../../../../../rtems/c/src/lib/libbsp/powerpc/motorola_ (nil)) (insn 36 35 37 2 (set (reg/v:SI 0 0 [orig:239 s2 ] [239]) (lshiftrt:SI (reg/v:SI 3 3 [orig:264 adler ] [264]) (const_int 16 [0x10]))) ../../../../../../../../../rtems/c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/../../../powerpc/shared/b (nil)) (debug_insn 37 36 39 2 (var_location:SI s2 (reg/v:SI 0 0 [orig:239 s2 ] [239])) ../../../../../../../../../rtems/c/src/lib/libbsp/powerpc/motorola_ (nil)) in bb2 and decide to move insn 34 and 36 to the start of bb3, before the patch we'd keep the debug insns untouched, while with the patch we get: (debug_insn 365 38 35 2 (var_location:SI D#38 (and:SI (reg/v:SI 3 3 [orig:264 adler ] [264]) (const_int 65535 [0xffff]))) -1 (nil)) (debug_insn 35 365 363 2 (var_location:SI s1 (debug_expr:SI D#38)) ../../../../../../../../../rtems/c/src/lib/libbsp/powerpc/motorola_powerpc/bootl (nil)) (debug_insn 363 35 37 2 (var_location:SI D#37 (lshiftrt:SI (reg/v:SI 3 3 [orig:264 adler ] [264]) (const_int 16 [0x10]))) -1 (nil)) (debug_insn 37 363 39 2 (var_location:SI s2 (debug_expr:SI D#37)) ../../../../../../../../../rtems/c/src/lib/libbsp/powerpc/motorola_powerpc/bootlo (nil)) in bb2. Even on x86_64-linux I saw even on this testcase improvement in debug info coverage (it didn't end up being wrong debug there, but one of the variables used to be without the patch in certain range. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2016-01-19 Jakub Jelinek PR debug/65779 * shrink-wrap.c: Include valtrack.h. (move_insn_for_shrink_wrap): Add DEBUG argument. If MAY_HAVE_DEBUG_INSNS, call dead_debug_add on DEBUG_INSNs in between insn and where it will be moved to. Call dead_debug_insert_temp. (prepare_shrink_wrap): Adjust caller. Call dead_debug_local_init first and dead_debug_local_finish at the end. For uses and defs bitmap, handle all regs in between REGNO and END_REGNO, not just the first one. * gcc.dg/pr65779.c: New test. --- gcc/shrink-wrap.c.jj 2016-01-08 07:31:10.000000000 +0100 +++ gcc/shrink-wrap.c 2016-01-18 20:06:53.029487254 +0100 @@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. #include "shrink-wrap.h" #include "regcprop.h" #include "rtl-iter.h" +#include "valtrack.h" /* Return true if INSN requires the stack frame to be set up. @@ -149,7 +150,8 @@ static bool move_insn_for_shrink_wrap (basic_block bb, rtx_insn *insn, const HARD_REG_SET uses, const HARD_REG_SET defs, - bool *split_p) + bool *split_p, + struct dead_debug_local *debug) { rtx set, src, dest; bitmap live_out, live_in, bb_uses, bb_defs; @@ -158,6 +160,8 @@ move_insn_for_shrink_wrap (basic_block b unsigned int end_sregno = FIRST_PSEUDO_REGISTER; basic_block next_block; edge live_edge; + rtx_insn *dinsn; + df_ref def; /* Look for a simple register assignment. We don't use single_set here because we can't deal with any CLOBBERs, USEs, or REG_UNUSED secondary @@ -298,6 +302,19 @@ move_insn_for_shrink_wrap (basic_block b *split_p = true; } + if (MAY_HAVE_DEBUG_INSNS) + { + for (dinsn = BB_END (bb); dinsn != insn; dinsn = PREV_INSN (dinsn)) + if (DEBUG_INSN_P (dinsn)) + { + df_ref use; + FOR_EACH_INSN_USE (use, dinsn) + if (refers_to_regno_p (dregno, end_dregno, + DF_REF_REG (use), (rtx *) NULL)) + dead_debug_add (debug, use, DF_REF_REGNO (use)); + } + } + /* At this point we are committed to moving INSN, but let's try to move it as far as we can. */ do @@ -363,6 +380,18 @@ move_insn_for_shrink_wrap (basic_block b if (!live_edge || EDGE_COUNT (live_edge->dest->preds) > 1) break; next_block = live_edge->dest; + if (MAY_HAVE_DEBUG_INSNS) + { + FOR_BB_INSNS_REVERSE (bb, dinsn) + if (DEBUG_INSN_P (dinsn)) + { + df_ref use; + FOR_EACH_INSN_USE (use, dinsn) + if (refers_to_regno_p (dregno, end_dregno, + DF_REF_REG (use), (rtx *) NULL)) + dead_debug_add (debug, use, DF_REF_REGNO (use)); + } + } } } while (next_block); @@ -384,6 +413,12 @@ move_insn_for_shrink_wrap (basic_block b SET_REGNO_REG_SET (bb_uses, i); } + /* Insert debug temps for dead REGs used in subsequent debug insns. */ + if (debug->used && !bitmap_empty_p (debug->used)) + FOR_EACH_INSN_DEF (def, insn) + dead_debug_insert_temp (debug, DF_REF_REGNO (def), insn, + DEBUG_TEMP_BEFORE_WITH_VALUE); + emit_insn_after (PATTERN (insn), bb_note (bb)); delete_insn (insn); return true; @@ -404,6 +439,8 @@ prepare_shrink_wrap (basic_block entry_b HARD_REG_SET uses, defs; df_ref def, use; bool split_p = false; + unsigned int i; + struct dead_debug_local debug; if (JUMP_P (BB_END (entry_block))) { @@ -414,19 +451,22 @@ prepare_shrink_wrap (basic_block entry_b copyprop_hardreg_forward_bb_without_debug_insn (entry_block); } + dead_debug_local_init (&debug, NULL, NULL); CLEAR_HARD_REG_SET (uses); CLEAR_HARD_REG_SET (defs); + FOR_BB_INSNS_REVERSE_SAFE (entry_block, insn, curr) if (NONDEBUG_INSN_P (insn) && !move_insn_for_shrink_wrap (entry_block, insn, uses, defs, - &split_p)) + &split_p, &debug)) { /* Add all defined registers to DEFs. */ FOR_EACH_INSN_DEF (def, insn) { x = DF_REF_REG (def); if (REG_P (x) && HARD_REGISTER_P (x)) - SET_HARD_REG_BIT (defs, REGNO (x)); + for (i = REGNO (x); i < END_REGNO (x); i++) + SET_HARD_REG_BIT (defs, i); } /* Add all used registers to USESs. */ @@ -434,9 +474,12 @@ prepare_shrink_wrap (basic_block entry_b { x = DF_REF_REG (use); if (REG_P (x) && HARD_REGISTER_P (x)) - SET_HARD_REG_BIT (uses, REGNO (x)); + for (i = REGNO (x); i < END_REGNO (x); i++) + SET_HARD_REG_BIT (uses, i); } } + + dead_debug_local_finish (&debug, NULL); } /* Return whether basic block PRO can get the prologue. It can not if it --- gcc/testsuite/gcc.dg/pr65779.c.jj 2016-01-18 20:27:48.906187675 +0100 +++ gcc/testsuite/gcc.dg/pr65779.c 2016-01-18 20:20:02.000000000 +0100 @@ -0,0 +1,42 @@ +/* PR debug/65779 */ +/* { dg-do assemble } */ +/* { dg-options "-O2 -fcompare-debug" } */ + +unsigned long +foo (unsigned long x, unsigned char *y, unsigned int z) +{ + unsigned long a = x & 0xffff; + unsigned long b = (x >> 16) & 0xffff; + int k; + if (y == 0) return 1L; + while (z > 0) + { + k = z < 5552 ? z : 5552; + z -= k; + while (k >= 16) + { + a += *y++; b += a; + a += *y++; b += a; + a += *y++; b += a; + a += *y++; b += a; + a += *y++; b += a; + a += *y++; b += a; + a += *y++; b += a; + a += *y++; b += a; + a += *y++; b += a; + a += *y++; b += a; + a += *y++; b += a; + a += *y++; b += a; + a += *y++; b += a; + a += *y++; b += a; + a += *y++; b += a; + a += *y++; b += a; + k -= 16; + } + if (k != 0) + do { a += *y++; b += a; } while (--k); + a %= 65521L; + b %= 65521L; + } + return (b << 16) | a; +} Jakub