From patchwork Tue Oct 5 20:48:50 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 66863 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 C5E9BB70AB for ; Wed, 6 Oct 2010 07:47:21 +1100 (EST) Received: (qmail 4838 invoked by alias); 5 Oct 2010 20:47:14 -0000 Received: (qmail 4813 invoked by uid 22791); 5 Oct 2010 20:47:11 -0000 X-SWARE-Spam-Status: No, hits=-6.1 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, TW_DB, TW_TM, T_RP_MATCHES_RCVD 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; Tue, 05 Oct 2010 20:47:01 +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 o95KkxUS016691 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Tue, 5 Oct 2010 16:46:59 -0400 Received: from tyan-ft48-01.lab.bos.redhat.com (tyan-ft48-01.lab.bos.redhat.com [10.16.42.4]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o95Kkw59011871 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Tue, 5 Oct 2010 16:46:59 -0400 Received: from tyan-ft48-01.lab.bos.redhat.com (tyan-ft48-01.lab.bos.redhat.com [127.0.0.1]) by tyan-ft48-01.lab.bos.redhat.com (8.14.4/8.14.4) with ESMTP id o95Kmr6X019254; Tue, 5 Oct 2010 22:48:53 +0200 Received: (from jakub@localhost) by tyan-ft48-01.lab.bos.redhat.com (8.14.4/8.14.4/Submit) id o95Kmomk019252; Tue, 5 Oct 2010 22:48:50 +0200 Date: Tue, 5 Oct 2010 22:48:50 +0200 From: Jakub Jelinek To: Richard Guenther Cc: gcc-patches@gcc.gnu.org, Alexandre Oliva Subject: [PATCH] Don't reset debug stmts in delete_trivially_dead_insns unnecessarily Message-ID: <20101005204850.GC4127@tyan-ft48-01.lab.bos.redhat.com> Reply-To: Jakub Jelinek MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-12-10) X-IsSubscribed: yes 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 Hi! This patch implements something similar to what we do in DF to avoid resetting debug stmts, in particular if possible put a D#N temporary right before the to be deleted trivially dead insn and use the D#N DEBUG_EXPR in following DEBUG_INSNs instead of resetting them. Bootstrapped/regtested on x86_64-linux and i686-linux. Ok for trunk? In i686-linux bootstrap/regtest delete_trivially_dead_insns had to reset 18291 DEBUG_INSNs, but additional 19170 could be kept because of this patch, on x86_64-linux 20807 resets happened and 3503 could be kept. Still, even on x86_64-linux 180 DIEs in cc1plus got newly DW_AT_location which they didn't have before. 2010-10-05 Jakub Jelinek * cse.c (is_dead_reg): Change into inline function that is not called through for_each_rtx. (set_live_p): Adjust caller. (insn_live_p): Don't reset DEBUG_INSNs here. (struct dead_debug_insn_data): New data. (count_stores, is_dead_debug_insn, replace_dead_reg): New functions. (delete_trivially_dead_insns): If there is just one setter for the dead reg that is referenced by some DEBUG_INSNs, create a DEBUG_EXPR and add DEBUG_INSN for it right before the removed setter and use the DEBUG_EXPR instead of the dead pseudo. Jakub --- gcc/cse.c.jj 2010-10-01 12:39:13.000000000 +0200 +++ gcc/cse.c 2010-10-05 19:01:34.000000000 +0200 @@ -6687,12 +6687,9 @@ count_reg_usage (rtx x, int *counts, rtx /* Return true if a register is dead. Can be used in for_each_rtx. */ -static int -is_dead_reg (rtx *loc, void *data) +static inline int +is_dead_reg (rtx x, int *counts) { - rtx x = *loc; - int *counts = (int *)data; - return (REG_P (x) && REGNO (x) >= FIRST_PSEUDO_REGISTER && counts[REGNO (x)] == 0); @@ -6718,7 +6715,7 @@ set_live_p (rtx set, rtx insn ATTRIBUTE_ || !reg_referenced_p (cc0_rtx, PATTERN (tem)))) return false; #endif - else if (!is_dead_reg (&SET_DEST (set), counts) + else if (!is_dead_reg (SET_DEST (set), counts) || side_effects_p (SET_SRC (set))) return true; return false; @@ -6762,21 +6759,67 @@ insn_live_p (rtx insn, int *counts) else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next)) return false; - /* If this debug insn references a dead register, drop the - location expression for now. ??? We could try to find the - def and see if propagation is possible. */ - if (for_each_rtx (&INSN_VAR_LOCATION_LOC (insn), is_dead_reg, counts)) - { - INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC (); - df_insn_rescan (insn); - } - return true; } else return true; } +/* Count the number of stores into pseudo. */ + +static void +count_stores (rtx x, const_rtx set ATTRIBUTE_UNUSED, void *data) +{ + int *counts = (int *) data; + if (REG_P (x) && REGNO (x) >= FIRST_PSEUDO_REGISTER) + counts[REGNO (x)]++; +} + +struct dead_debug_insn_data +{ + int *counts; + rtx *replacements; + bool seen_repl; +}; + +/* Return if a DEBUG_INSN needs to be reset because some dead + pseudo doesn't have a replacement. */ + +static int +is_dead_debug_insn (rtx *loc, void *data) +{ + rtx x = *loc; + struct dead_debug_insn_data *ddid = (struct dead_debug_insn_data *) data; + + if (is_dead_reg (x, ddid->counts)) + { + if (ddid->replacements && ddid->replacements[REGNO (x)] != NULL_RTX) + ddid->seen_repl = true; + else + return 1; + } + return 0; +} + +/* Replace a dead pseudo in a DEBUG_INSN with replacement DEBUG_EXPR. */ + +static rtx +replace_dead_reg (rtx x, const_rtx old_rtx ATTRIBUTE_UNUSED, void *data) +{ + rtx *replacements = (rtx *) data; + + if (REG_P (x) + && REGNO (x) >= FIRST_PSEUDO_REGISTER + && replacements[REGNO (x)] != NULL_RTX) + { + if (GET_MODE (x) == GET_MODE (replacements[REGNO (x)])) + return replacements[REGNO (x)]; + return lowpart_subreg (GET_MODE (x), replacements[REGNO (x)], + GET_MODE (replacements[REGNO (x)])); + } + return NULL_RTX; +} + /* Scan all the insns and delete any that are dead; i.e., they store a register that is never used or they copy a register to itself. @@ -6790,15 +6833,31 @@ delete_trivially_dead_insns (rtx insns, { int *counts; rtx insn, prev; + rtx *replacements = NULL; int ndead = 0; timevar_push (TV_DELETE_TRIVIALLY_DEAD); /* First count the number of times each register is used. */ - counts = XCNEWVEC (int, nreg); - for (insn = insns; insn; insn = NEXT_INSN (insn)) - if (INSN_P (insn)) - count_reg_usage (insn, counts, NULL_RTX, 1); - + if (MAY_HAVE_DEBUG_INSNS) + { + counts = XCNEWVEC (int, nreg * 3); + for (insn = insns; insn; insn = NEXT_INSN (insn)) + if (DEBUG_INSN_P (insn)) + count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg, + NULL_RTX, 1); + else if (INSN_P (insn)) + { + count_reg_usage (insn, counts, NULL_RTX, 1); + note_stores (PATTERN (insn), count_stores, counts + nreg * 2); + } + } + else + { + counts = XCNEWVEC (int, nreg); + for (insn = insns; insn; insn = NEXT_INSN (insn)) + if (INSN_P (insn)) + count_reg_usage (insn, counts, NULL_RTX, 1); + } /* Go from the last insn to the first and delete insns that only set unused registers or copy a register to itself. As we delete an insn, remove usage counts for registers it uses. @@ -6821,12 +6880,80 @@ delete_trivially_dead_insns (rtx insns, if (! live_insn && dbg_cnt (delete_trivial_dead)) { - count_reg_usage (insn, counts, NULL_RTX, -1); + if (DEBUG_INSN_P (insn)) + count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg, + NULL_RTX, -1); + else + { + rtx set; + if (MAY_HAVE_DEBUG_INSNS + && (set = single_set (insn)) != NULL_RTX + && is_dead_reg (SET_DEST (set), counts) + /* Used at least once in some DEBUG_INSN. */ + && counts[REGNO (SET_DEST (set)) + nreg] > 0 + /* And set exactly once. */ + && counts[REGNO (SET_DEST (set)) + nreg * 2] == 1 + && !side_effects_p (SET_SRC (set)) + && asm_noperands (PATTERN (insn)) < 0) + { + rtx dval, bind; + + /* Create DEBUG_EXPR (and DEBUG_EXPR_DECL). */ + dval = make_debug_expr_from_rtl (SET_DEST (set)); + + /* Emit a debug bind insn before the insn in which + reg dies. */ + bind = gen_rtx_VAR_LOCATION (GET_MODE (SET_DEST (set)), + DEBUG_EXPR_TREE_DECL (dval), + SET_SRC (set), + VAR_INIT_STATUS_INITIALIZED); + count_reg_usage (bind, counts + nreg, NULL_RTX, 1); + + bind = emit_debug_insn_before (bind, insn); + df_insn_rescan (bind); + + if (replacements == NULL) + replacements = XCNEWVEC (rtx, nreg); + replacements[REGNO (SET_DEST (set))] = dval; + } + + count_reg_usage (insn, counts, NULL_RTX, -1); + ndead++; + } delete_insn_and_edges (insn); - ndead++; } } + if (MAY_HAVE_DEBUG_INSNS) + { + struct dead_debug_insn_data ddid; + ddid.counts = counts; + ddid.replacements = replacements; + for (insn = get_last_insn (); insn; insn = PREV_INSN (insn)) + if (DEBUG_INSN_P (insn)) + { + /* If this debug insn references a dead register that wasn't replaced + with an DEBUG_EXPR, reset the DEBUG_INSN. */ + ddid.seen_repl = false; + if (for_each_rtx (&INSN_VAR_LOCATION_LOC (insn), + is_dead_debug_insn, &ddid)) + { + INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC (); + df_insn_rescan (insn); + } + else if (ddid.seen_repl) + { + INSN_VAR_LOCATION_LOC (insn) + = simplify_replace_fn_rtx (INSN_VAR_LOCATION_LOC (insn), + NULL_RTX, replace_dead_reg, + replacements); + df_insn_rescan (insn); + } + } + if (replacements) + free (replacements); + } + if (dump_file && ndead) fprintf (dump_file, "Deleted %i trivially dead insns\n", ndead);