From patchwork Thu Aug 25 19:02:26 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 111638 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 A66E3B6F8A for ; Fri, 26 Aug 2011 05:02:57 +1000 (EST) Received: (qmail 10739 invoked by alias); 25 Aug 2011 19:02:55 -0000 Received: (qmail 10731 invoked by uid 22791); 25 Aug 2011 19:02:54 -0000 X-SWARE-Spam-Status: No, hits=-6.6 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, SPF_HELO_PASS 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; Thu, 25 Aug 2011 19:02:36 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p7PJ2ZD1012160 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 25 Aug 2011 15:02:35 -0400 Received: from pebble.twiddle.home (ovpn-113-152.phx2.redhat.com [10.3.113.152]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p7PJ2Yhe004933 for ; Thu, 25 Aug 2011 15:02:34 -0400 Message-ID: <4E569C42.9080101@redhat.com> Date: Thu, 25 Aug 2011 09:02:26 -1000 From: Richard Henderson User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.20) Gecko/20110817 Fedora/3.1.12-1.fc14 Thunderbird/3.1.12 MIME-Version: 1.0 To: GCC Patches Subject: Fix pr 50132 and 49864 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 These are both REG_ARGS_SIZE mis-match problems. The 49864 problem is caused by cross-jumping doing the wrong thing. The 50132 problem is caused by fixup_args_size_notes think-o where we failed to properly handle pops. Techinically I should have split these changes apart, but I tested them together and the splitting would have just been make-work. Tested on x86_64-linux. Committed. r~ PR 50132 PR 49864 * cfgcleanup.c (old_insns_match_p): Don't allow cross-jump for non-constant stack adjutment. * expr.c (find_args_size_adjust): Break out from ... (fixup_args_size_notes): ... here. * rtl.h (find_args_size_adjust): Declare. diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c index 7173013..396057c 100644 --- a/gcc/cfgcleanup.c +++ b/gcc/cfgcleanup.c @@ -1081,11 +1081,20 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2) /* ??? Do not allow cross-jumping between different stack levels. */ p1 = find_reg_note (i1, REG_ARGS_SIZE, NULL); p2 = find_reg_note (i2, REG_ARGS_SIZE, NULL); - if (p1) - p1 = XEXP (p1, 0); - if (p2) - p2 = XEXP (p2, 0); - if (!rtx_equal_p (p1, p2)) + if (p1 && p2) + { + p1 = XEXP (p1, 0); + p2 = XEXP (p2, 0); + if (!rtx_equal_p (p1, p2)) + return dir_none; + + /* ??? Worse, this adjustment had better be constant lest we + have differing incoming stack levels. */ + if (!frame_pointer_needed + && find_args_size_adjust (i1) == HOST_WIDE_INT_MIN) + return dir_none; + } + else if (p1 || p2) return dir_none; p1 = PATTERN (i1); diff --git a/gcc/expr.c b/gcc/expr.c index ee16b6a..a6746d1 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -3548,131 +3548,151 @@ mem_autoinc_base (rtx mem) verified, via immediate operand or auto-inc. If the adjustment cannot be trivially extracted, the return value is INT_MIN. */ -int -fixup_args_size_notes (rtx prev, rtx last, int end_args_size) +HOST_WIDE_INT +find_args_size_adjust (rtx insn) { - int args_size = end_args_size; - bool saw_unknown = false; - rtx insn; + rtx dest, set, pat; + int i; - for (insn = last; insn != prev; insn = PREV_INSN (insn)) - { - rtx dest, set, pat; - HOST_WIDE_INT this_delta = 0; - int i; + pat = PATTERN (insn); + set = NULL; - if (!NONDEBUG_INSN_P (insn)) - continue; - pat = PATTERN (insn); - set = NULL; + /* Look for a call_pop pattern. */ + if (CALL_P (insn)) + { + /* We have to allow non-call_pop patterns for the case + of emit_single_push_insn of a TLS address. */ + if (GET_CODE (pat) != PARALLEL) + return 0; - /* Look for a call_pop pattern. */ - if (CALL_P (insn)) + /* All call_pop have a stack pointer adjust in the parallel. + The call itself is always first, and the stack adjust is + usually last, so search from the end. */ + for (i = XVECLEN (pat, 0) - 1; i > 0; --i) { - /* We have to allow non-call_pop patterns for the case - of emit_single_push_insn of a TLS address. */ - if (GET_CODE (pat) != PARALLEL) - continue; - - /* All call_pop have a stack pointer adjust in the parallel. - The call itself is always first, and the stack adjust is - usually last, so search from the end. */ - for (i = XVECLEN (pat, 0) - 1; i > 0; --i) - { - set = XVECEXP (pat, 0, i); - if (GET_CODE (set) != SET) - continue; - dest = SET_DEST (set); - if (dest == stack_pointer_rtx) - break; - } - /* We'd better have found the stack pointer adjust. */ - if (i == 0) + set = XVECEXP (pat, 0, i); + if (GET_CODE (set) != SET) continue; - /* Fall through to process the extracted SET and DEST - as if it was a standalone insn. */ + dest = SET_DEST (set); + if (dest == stack_pointer_rtx) + break; } - else if (GET_CODE (pat) == SET) - set = pat; - else if ((set = single_set (insn)) != NULL) - ; - else if (GET_CODE (pat) == PARALLEL) + /* We'd better have found the stack pointer adjust. */ + if (i == 0) + return 0; + /* Fall through to process the extracted SET and DEST + as if it was a standalone insn. */ + } + else if (GET_CODE (pat) == SET) + set = pat; + else if ((set = single_set (insn)) != NULL) + ; + else if (GET_CODE (pat) == PARALLEL) + { + /* ??? Some older ports use a parallel with a stack adjust + and a store for a PUSH_ROUNDING pattern, rather than a + PRE/POST_MODIFY rtx. Don't force them to update yet... */ + /* ??? See h8300 and m68k, pushqi1. */ + for (i = XVECLEN (pat, 0) - 1; i >= 0; --i) { - /* ??? Some older ports use a parallel with a stack adjust - and a store for a PUSH_ROUNDING pattern, rather than a - PRE/POST_MODIFY rtx. Don't force them to update yet... */ - /* ??? See h8300 and m68k, pushqi1. */ - for (i = XVECLEN (pat, 0) - 1; i >= 0; --i) - { - set = XVECEXP (pat, 0, i); - if (GET_CODE (set) != SET) - continue; - dest = SET_DEST (set); - if (dest == stack_pointer_rtx) - break; - - /* We do not expect an auto-inc of the sp in the parallel. */ - gcc_checking_assert (mem_autoinc_base (dest) - != stack_pointer_rtx); - gcc_checking_assert (mem_autoinc_base (SET_SRC (set)) - != stack_pointer_rtx); - } - if (i < 0) + set = XVECEXP (pat, 0, i); + if (GET_CODE (set) != SET) continue; + dest = SET_DEST (set); + if (dest == stack_pointer_rtx) + break; + + /* We do not expect an auto-inc of the sp in the parallel. */ + gcc_checking_assert (mem_autoinc_base (dest) != stack_pointer_rtx); + gcc_checking_assert (mem_autoinc_base (SET_SRC (set)) + != stack_pointer_rtx); } + if (i < 0) + return 0; + } + else + return 0; + + dest = SET_DEST (set); + + /* Look for direct modifications of the stack pointer. */ + if (REG_P (dest) && REGNO (dest) == STACK_POINTER_REGNUM) + { + /* Look for a trivial adjustment, otherwise assume nothing. */ + /* Note that the SPU restore_stack_block pattern refers to + the stack pointer in V4SImode. Consider that non-trivial. */ + if (SCALAR_INT_MODE_P (GET_MODE (dest)) + && GET_CODE (SET_SRC (set)) == PLUS + && XEXP (SET_SRC (set), 0) == stack_pointer_rtx + && CONST_INT_P (XEXP (SET_SRC (set), 1))) + return INTVAL (XEXP (SET_SRC (set), 1)); + /* ??? Reload can generate no-op moves, which will be cleaned + up later. Recognize it and continue searching. */ + else if (rtx_equal_p (dest, SET_SRC (set))) + return 0; else - continue; - dest = SET_DEST (set); - - /* Look for direct modifications of the stack pointer. */ - if (REG_P (dest) && REGNO (dest) == STACK_POINTER_REGNUM) - { - gcc_assert (!saw_unknown); - /* Look for a trivial adjustment, otherwise assume nothing. */ - /* Note that the SPU restore_stack_block pattern refers to - the stack pointer in V4SImode. Consider that non-trivial. */ - if (SCALAR_INT_MODE_P (GET_MODE (dest)) - && GET_CODE (SET_SRC (set)) == PLUS - && XEXP (SET_SRC (set), 0) == stack_pointer_rtx - && CONST_INT_P (XEXP (SET_SRC (set), 1))) - this_delta = INTVAL (XEXP (SET_SRC (set), 1)); - /* ??? Reload can generate no-op moves, which will be cleaned - up later. Recognize it and continue searching. */ - else if (rtx_equal_p (dest, SET_SRC (set))) - this_delta = 0; - else - saw_unknown = true; - } + return HOST_WIDE_INT_MIN; + } + else + { + rtx mem, addr; + /* Otherwise only think about autoinc patterns. */ - else if (mem_autoinc_base (dest) == stack_pointer_rtx) + if (mem_autoinc_base (dest) == stack_pointer_rtx) { - rtx addr = XEXP (dest, 0); - gcc_assert (!saw_unknown); - switch (GET_CODE (addr)) - { - case PRE_INC: - case POST_INC: - this_delta = GET_MODE_SIZE (GET_MODE (dest)); - break; - case PRE_DEC: - case POST_DEC: - this_delta = -GET_MODE_SIZE (GET_MODE (dest)); - break; - case PRE_MODIFY: - case POST_MODIFY: - addr = XEXP (addr, 1); - gcc_assert (GET_CODE (addr) == PLUS); - gcc_assert (XEXP (addr, 0) == stack_pointer_rtx); - gcc_assert (CONST_INT_P (XEXP (addr, 1))); - this_delta = INTVAL (XEXP (addr, 1)); - break; - default: - gcc_unreachable (); - } + mem = dest; + gcc_checking_assert (mem_autoinc_base (SET_SRC (set)) + != stack_pointer_rtx); } + else if (mem_autoinc_base (SET_SRC (set)) == stack_pointer_rtx) + mem = SET_SRC (set); else + return 0; + + addr = XEXP (mem, 0); + switch (GET_CODE (addr)) + { + case PRE_INC: + case POST_INC: + return GET_MODE_SIZE (GET_MODE (mem)); + case PRE_DEC: + case POST_DEC: + return -GET_MODE_SIZE (GET_MODE (mem)); + case PRE_MODIFY: + case POST_MODIFY: + addr = XEXP (addr, 1); + gcc_assert (GET_CODE (addr) == PLUS); + gcc_assert (XEXP (addr, 0) == stack_pointer_rtx); + gcc_assert (CONST_INT_P (XEXP (addr, 1))); + return INTVAL (XEXP (addr, 1)); + default: + gcc_unreachable (); + } + } +} + +int +fixup_args_size_notes (rtx prev, rtx last, int end_args_size) +{ + int args_size = end_args_size; + bool saw_unknown = false; + rtx insn; + + for (insn = last; insn != prev; insn = PREV_INSN (insn)) + { + HOST_WIDE_INT this_delta; + + if (!NONDEBUG_INSN_P (insn)) + continue; + + this_delta = find_args_size_adjust (insn); + if (this_delta == 0) continue; + gcc_assert (!saw_unknown); + if (this_delta == HOST_WIDE_INT_MIN) + saw_unknown = true; + add_reg_note (insn, REG_ARGS_SIZE, GEN_INT (args_size)); #ifdef STACK_GROWS_DOWNWARD this_delta = -this_delta; diff --git a/gcc/rtl.h b/gcc/rtl.h index e8aa7ab..7f86389 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -2508,6 +2508,7 @@ extern void emit_jump (rtx); /* In expr.c */ extern rtx move_by_pieces (rtx, rtx, unsigned HOST_WIDE_INT, unsigned int, int); +extern HOST_WIDE_INT find_args_size_adjust (rtx); extern int fixup_args_size_notes (rtx, rtx, int); /* In cfgrtl.c */