From patchwork Thu Sep 22 17:05:07 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bernd Schmidt X-Patchwork-Id: 115970 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 2BE94B6F81 for ; Fri, 23 Sep 2011 03:05:34 +1000 (EST) Received: (qmail 20507 invoked by alias); 22 Sep 2011 17:05:32 -0000 Received: (qmail 20498 invoked by uid 22791); 22 Sep 2011 17:05:30 -0000 X-SWARE-Spam-Status: No, hits=-1.0 required=5.0 tests=AWL, BAYES_00, FROM_12LTRDOM X-Spam-Check-By: sourceware.org Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 22 Sep 2011 17:05:12 +0000 Received: from nat-ies.mentorg.com ([192.94.31.2] helo=EU1-MAIL.mgc.mentorg.com) by relay1.mentorg.com with esmtp id 1R6mhz-0003qP-VL from Bernd_Schmidt@mentor.com for gcc-patches@gcc.gnu.org; Thu, 22 Sep 2011 10:05:12 -0700 Received: from [127.0.0.1] ([172.16.63.104]) by EU1-MAIL.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.1830); Thu, 22 Sep 2011 18:05:13 +0100 Message-ID: <4E7B6AC3.9040800@codesourcery.com> Date: Thu, 22 Sep 2011 19:05:07 +0200 From: Bernd Schmidt User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.20) Gecko/20110920 Lightning/1.0b3pre Thunderbird/3.1.12 MIME-Version: 1.0 To: GCC Patches CC: Tom de Vries Subject: reload_reg_reaches_end_p fix 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 This fixes a reload problem found by Tom de Vries while testing another patch. An analysis of the problem is in PR50249. Essentially, we have multiple reloads with the same type, for the same operand, feeding each other and reusing the same register: Reload 1: reload_in (SI) = (reg/f:SI 10 sl [588]) BASE_REGS, RELOAD_FOR_OPERAND_ADDRESS (opnum = 0) reload_in_reg: (reg/f:SI 10 sl [588]) reload_reg_rtx: (reg:SI 1 r1) Reload 2: reload_in (SI) = (mem:SI (reg/f:SI 10 sl [588])) LO_REGS, RELOAD_FOR_OPERAND_ADDRESS (opnum = 0), can't combine reload_in_reg: (reg:SI 379) reload_reg_rtx: (reg:SI 1 r1) One might wonder why the first reload isn't using RELOAD_FOR_OPADDR_ADDR. All the reload types are rewritten in find_reloads and the last stage of that follows this comment: /* Scan all the reloads, and check for RELOAD_FOR_OPERAND_ADDRESS reloads. If we have more than one, then convert all RELOAD_FOR_OPADDR_ADDR reloads to RELOAD_FOR_OPERAND_ADDRESS reloads. So, presumably this is valid, and it looks like reload_reg_reaches_end simply does not deal with this case. The following patch just adds a loop to look for other reloads that look the same in this way. I've bootstrapped and tested it on i686-linux; Tom has tested a few other targets (although I'm not totally sure for which gcc version); it appears to fix some Thumb libstdc++ testsuite failures. Thoughts? I plan to install this tomorrow or so unless someone sees a problem. Bernd PR rtl-optimization/50249 * reload1.c (reload_reg_reaches_end_p): Accept a reloadnum argument instead of opnum and type. All callers changed. Remove useless declaration. Search forward for other reloads of the same type for the same operand using the same register; if any are found, return false. (reload_regs_reach_end_p): Same argument changes; all callers changed. Index: reload1.c =================================================================== --- reload1.c (revision 178583) +++ reload1.c (working copy) @@ -396,7 +396,6 @@ static int reload_reg_free_for_value_p ( rtx, rtx, int, int); static int free_for_value_p (int, enum machine_mode, int, enum reload_type, rtx, rtx, int, int); -static int reload_reg_reaches_end_p (unsigned int, int, enum reload_type); static int allocate_reload_reg (struct insn_chain *, int, int); static int conflicts_with_override (rtx); static void failed_reload (rtx, int); @@ -5346,19 +5345,37 @@ reload_reg_free_p (unsigned int regno, i } } -/* Return 1 if the value in reload reg REGNO, as used by a reload - needed for the part of the insn specified by OPNUM and TYPE, - is still available in REGNO at the end of the insn. +/* Return 1 if the value in reload reg REGNO, as used by the reload with + the number RELOADNUM, is still available in REGNO at the end of the insn. We can assume that the reload reg was already tested for availability at the time it is needed, and we should not check this again, in case the reg has already been marked in use. */ static int -reload_reg_reaches_end_p (unsigned int regno, int opnum, enum reload_type type) +reload_reg_reaches_end_p (unsigned int regno, int reloadnum) { + int opnum = rld[reloadnum].opnum; + enum reload_type type = rld[reloadnum].when_needed; int i; + /* See if there is a reload with the same type for this operand, using + the same register. This case is not handled by the code below. */ + for (i = reloadnum + 1; i < n_reloads; i++) + { + rtx reg; + int nregs; + + if (rld[i].opnum != opnum || rld[i].when_needed != type) + continue; + reg = rld[i].reg_rtx; + if (reg == NULL_RTX) + continue; + nregs = hard_regno_nregs[REGNO (reg)][GET_MODE (reg)]; + if (regno >= REGNO (reg) && regno < REGNO (reg) + nregs) + return 0; + } + switch (type) { case RELOAD_OTHER: @@ -5485,13 +5502,12 @@ reload_reg_reaches_end_p (unsigned int r every register in the range [REGNO, REGNO + NREGS). */ static bool -reload_regs_reach_end_p (unsigned int regno, int nregs, - int opnum, enum reload_type type) +reload_regs_reach_end_p (unsigned int regno, int nregs, int reloadnum) { int i; for (i = 0; i < nregs; i++) - if (!reload_reg_reaches_end_p (regno + i, opnum, type)) + if (!reload_reg_reaches_end_p (regno + i, reloadnum)) return false; return true; } @@ -8103,8 +8119,7 @@ emit_reload_insns (struct insn_chain *ch /* For a multi register reload, we need to check if all or part of the value lives to the end. */ for (k = 0; k < nr; k++) - if (reload_reg_reaches_end_p (i + k, rld[r].opnum, - rld[r].when_needed)) + if (reload_reg_reaches_end_p (i + k, r)) CLEAR_HARD_REG_BIT (reg_reloaded_valid, i + k); /* Maybe the spill reg contains a copy of reload_out. */ @@ -8135,8 +8150,7 @@ emit_reload_insns (struct insn_chain *ch mode = GET_MODE (reg); regno = REGNO (reg); nregs = hard_regno_nregs[regno][mode]; - if (reload_regs_reach_end_p (regno, nregs, rld[r].opnum, - rld[r].when_needed)) + if (reload_regs_reach_end_p (regno, nregs, r)) { rtx out = (REG_P (rld[r].out) ? rld[r].out @@ -8208,8 +8222,7 @@ emit_reload_insns (struct insn_chain *ch mode = GET_MODE (reg); regno = REGNO (reg); nregs = hard_regno_nregs[regno][mode]; - if (reload_regs_reach_end_p (regno, nregs, rld[r].opnum, - rld[r].when_needed)) + if (reload_regs_reach_end_p (regno, nregs, r)) { int in_regno; int in_nregs;