From patchwork Mon Jan 17 15:34:11 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Oliva X-Patchwork-Id: 79193 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]) by ozlabs.org (Postfix) with SMTP id D7030B70F1 for ; Tue, 18 Jan 2011 02:34:30 +1100 (EST) Received: (qmail 6092 invoked by alias); 17 Jan 2011 15:34:27 -0000 Received: (qmail 5093 invoked by uid 22791); 17 Jan 2011 15:34:24 -0000 X-SWARE-Spam-Status: No, hits=-5.4 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, TW_TM, T_RP_MATCHES_RCVD, T_TVD_MIME_NO_HEADERS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 17 Jan 2011 15:34:19 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id p0HFYIND014755 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 17 Jan 2011 10:34:18 -0500 Received: from freie.oliva.athome.lsd.ic.unicamp.br (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id p0HFYG1U008193 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Mon, 17 Jan 2011 10:34:17 -0500 Received: from livre.localdomain (livre-to-gw.oliva.athome.lsd.ic.unicamp.br [172.31.160.19]) by freie.oliva.athome.lsd.ic.unicamp.br (8.14.4/8.14.4) with ESMTP id p0HFYDmk020088 for ; Mon, 17 Jan 2011 13:34:14 -0200 Received: from livre.localdomain (aoliva@localhost [127.0.0.1]) by livre.localdomain (8.14.3/8.14.3/Debian-5+lenny1) with ESMTP id p0HFYDKi001563; Mon, 17 Jan 2011 13:34:13 -0200 Received: (from aoliva@localhost) by livre.localdomain (8.14.3/8.14.3/Submit) id p0HFYBUB001561; Mon, 17 Jan 2011 13:34:11 -0200 From: Alexandre Oliva To: gcc-patches@gcc.gnu.org Subject: [PR debug/46240] don't introduce debug bind stmts at merge edges Date: Mon, 17 Jan 2011 13:34:11 -0200 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 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 A throwing call must be at the end of a BB, right? Well, then... what if we need to insert a debug bind stmt right after the call, because the result of the call is assigned to a user variable? If the fallthrough edge has a single pred, as usual, no problem, inserting on the edge amounts to inserting in the beginning of the subsequent block. However, if there's more than one predecessor, we can't insert the debug bind stmt at all, because inserting at the edge would amount to creating a new BB just for this one debug stmt, which would change the CFG and trigger undesirable codegen differences. We used to guard against fallthrough BBs without a single predecessor, but now that I see it's possible, I've reworked the code to deal with this situation. We still don't emit the debug bind stmt, but that's because we don't have to: if we're getting to a confluence point that joins the path with the call, that set a user variable, and another in which the assignment wasn't present, there is going to be a PHI node there, and there will be a debug bind stmt corresponding to that PHI node, so the debug bind stmt we'd emit would be redundant anyway. So, we can just refrain from emitting it, without loss of debug info. Yay! Here's the patch. Regstrapped on x86_64&32-linux-gnu. Ok to install? for gcc/ChangeLog from Alexandre Oliva PR debug/46240 * tree-into-ssa.c (maybe_register_def): Do not attempt to add debug bind stmt on merge edges. for gcc/testsuite/ChangeLog from Alexandre Oliva PR debug/46240 * g++.dg/debug/pr46240.cc: New. Index: gcc/tree-into-ssa.c =================================================================== --- gcc/tree-into-ssa.c.orig 2011-01-13 04:04:25.411690621 -0200 +++ gcc/tree-into-ssa.c 2011-01-13 05:34:29.762940340 -0200 @@ -1869,11 +1869,32 @@ maybe_register_def (def_operand_p def_p, gcc_assert (!ef); ef = e; } - gcc_assert (ef - && single_pred_p (ef->dest) - && !phi_nodes (ef->dest) - && ef->dest != EXIT_BLOCK_PTR); - gsi_insert_on_edge_immediate (ef, note); + /* If there are other predecessors to ef->dest, then + there must be PHI nodes for the modified + variable, and therefore there will be debug bind + stmts after the PHI nodes. The debug bind notes + we'd insert would force the creation of a new + block (diverging codegen) and be redundant with + the post-PHI bind stmts, so don't add them. + + As for the exit edge, there wouldn't be redundant + bind stmts, but there wouldn't be a PC to bind + them to either, so avoid diverging the CFG. */ + if (ef && single_pred_p (ef->dest) + && ef->dest != EXIT_BLOCK_PTR) + { + /* If there were PHI nodes in the node, we'd + have to make sure the value we're binding + doesn't need rewriting. But there shouldn't + be PHI nodes in a single-predecessor block, + so just check our assumption is correct. */ + gcc_checking_assert (!phi_nodes (ef->dest)); + gsi_insert_on_edge_immediate (ef, note); + } + else + gcc_checking_assert (ef + && (ef->dest == EXIT_BLOCK_PTR + || phi_nodes (ef->dest))); } else gsi_insert_after (&gsi, note, GSI_SAME_STMT); Index: gcc/testsuite/g++.dg/debug/pr46240.cc =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc/testsuite/g++.dg/debug/pr46240.cc 2011-01-13 04:42:40.460692068 -0200 @@ -0,0 +1,172 @@ +// { dg-do compile } +// { dg-options "-O3 -g" } + +template +T &max (T &a, T &b) +{ + if (a < b) return b; else return a; +} +int foo (double); +struct S +{ + struct T + { + int dims, count; + T (int, int) : dims (), count () {} + }; + T *rep; + S () {} + S (int r, int c) : rep (new T (r, c)) {} + ~S () { delete rep; } +}; +template +struct U +{ + static T epsilon () throw (); +}; +template +struct V +{ + struct W + { + T * data; + int count; + W (int n) : data (new T[n]), count () {} + }; + V::W *rep; + S dimensions; + int slice_len; + V (S s) : rep (new V ::W (get_size (s))) {} + int capacity () { return slice_len; } + int get_size (S); +}; +template +struct Z : public V +{ + Z () : V (S (0, 0)) {} + Z (int r, int c) : V (S (r, c)) {} +}; +template +struct A : public Z +{ + A () : Z () {} + A (int n, int m) : Z (n, m) {} +}; +template +struct B : public V +{ +}; +struct C : public A +{ + C () : A () {} + C (int r, int c) : A (r, c) {} +}; +struct D : public B +{ +}; +template +struct E +{ +}; +template +struct G : public E +{ +}; +struct H : public G +{ +}; +template +struct I +{ + R scl, sum; + void accum (R val) + { + R t = __builtin_fabs (val); + if (scl == t) + sum += 1; + } + operator R () { __builtin_sqrt (sum); return R (); } +}; +template +struct J +{ + template < class U > void accum (U val) {} + operator R () { return R (); } +}; +template +struct K +{ + R max; + template void accum (U val) + { + double z = __builtin_fabs (val); + max = ::max (max, z); + } + operator R () { return max; } +}; +template +struct L +{ + unsigned num; + template void accum (U) {} + operator R () { return num; } +}; +template +void bar (V &v, R &res, S acc) +{ + for (int i = 0; i < v.capacity (); i++) + acc.accum ((i)); + res = acc; +} +template +void bar (B &v, R) +{ + R res; + bar (v, res, I ()); +} +template +R bar (A &v, R p) +{ + R res; + if (p == 2) + bar (v, res, I ()); + else if (p == 1) + bar (v, res, J ()); + else if (p == sizeof (float) ? (p) : foo (p)) + { + if (p > 0) + bar (v, res, K ()); + } + else if (p == 0) + bar (v, res, L ()); + return res; +} +template +void +baz (CT m, R p, R tol, int maxiter, VectorT) +{ + VectorT y (0, 0), z (0, 1); + R q = 0; + R gamma = 0, gamma1 = 0; + gamma = bar (y, p); + (void) (bar (z, q) <= (gamma1 <= gamma)); +} +int a = 100; +template +void +test (CT m, R p, VectorT) +{ + VectorT x; + R sqrteps (U ::epsilon ()); + baz (m, p, sqrteps, a, x); +} +void +fn (D x, double p) +{ + bar (x, p); +} +void +fn (H x, double p) +{ + test (x, p, C ()); +}