From patchwork Mon Sep 27 14:27:14 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Modra X-Patchwork-Id: 65874 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 89DF9B70CD for ; Tue, 28 Sep 2010 00:27:37 +1000 (EST) Received: (qmail 20587 invoked by alias); 27 Sep 2010 14:27:34 -0000 Received: (qmail 20574 invoked by uid 22791); 27 Sep 2010 14:27:31 -0000 X-SWARE-Spam-Status: No, hits=-2.0 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE, T_TO_NO_BRKTS_FREEMAIL X-Spam-Check-By: sourceware.org Received: from mail-pv0-f175.google.com (HELO mail-pv0-f175.google.com) (74.125.83.175) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 27 Sep 2010 14:27:24 +0000 Received: by pvg6 with SMTP id 6so1525403pvg.20 for ; Mon, 27 Sep 2010 07:27:22 -0700 (PDT) Received: by 10.114.39.5 with SMTP id m5mr8560031wam.129.1285597642525; Mon, 27 Sep 2010 07:27:22 -0700 (PDT) Received: from bubble.grove.modra.org ([115.187.252.19]) by mx.google.com with ESMTPS id k23sm10589241waf.5.2010.09.27.07.27.18 (version=TLSv1/SSLv3 cipher=RC4-MD5); Mon, 27 Sep 2010 07:27:20 -0700 (PDT) Received: by bubble.grove.modra.org (Postfix, from userid 1000) id D0E47170C206; Mon, 27 Sep 2010 23:57:14 +0930 (CST) Date: Mon, 27 Sep 2010 23:57:14 +0930 From: Alan Modra To: gcc-patches@gcc.gnu.org Cc: David Edelsohn Subject: [RS6000] PR 45807 r2 eh_frame info error Message-ID: <20100927142714.GS16376@bubble.grove.modra.org> Mail-Followup-To: gcc-patches@gcc.gnu.org, David Edelsohn MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-06-14) 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 This patch makes sure that we emit eh_frame info for r2 at the place we actually save it. Previously, __builtin_unwind_init saved r2, while the prologue emitted the eh_frame info for r2. This opened a window for error, and Murphy did the rest. In unwind-dw2.c _Unwind_Resume_or_Rethrow we manage to insert a call before r2 is saved. See the PR for the ugly details. Powerpc64-linux bootstrap and regression test in progress. OK to apply assuming no regressions? I'd like to backport this to active branches too. PR target/45807 * config/rs6000/aix.h (SETUP_FRAME_ADDRESSES): Delete. * config/rs6000/linux64.h (SETUP_FRAME_ADDRESSES): Delete. * config/rs6000/rs6000-protos.h (rs6000_aix_emit_builtin_unwind_init): Delete. * config/rs6000/rs6000.c (rs6000_aix_emit_builtin_unwind_init): Delete. (rs6000_emit_prologue): Don't just create frame save info for r2, actually save r2. Index: gcc/config/rs6000/aix.h =================================================================== --- gcc/config/rs6000/aix.h (revision 164644) +++ gcc/config/rs6000/aix.h (working copy) @@ -207,13 +207,6 @@ /* And similarly for general purpose registers. */ #define GP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) < 32) -/* __throw will restore its own return address to be the same as the - return address of the function that the throw is being made to. - This is unfortunate, because we want to check the original - return address to see if we need to restore the TOC. - So we have to squirrel it away with this. */ -#define SETUP_FRAME_ADDRESSES() rs6000_aix_emit_builtin_unwind_init () - /* If the current unwind info (FS) does not contain explicit info saving R2, then we have to do a minor amount of code reading to figure out if it was saved. The big problem here is that the Index: gcc/config/rs6000/linux64.h =================================================================== --- gcc/config/rs6000/linux64.h (revision 164644) +++ gcc/config/rs6000/linux64.h (working copy) @@ -305,14 +308,6 @@ extern enum rs6000_cmodel cmodel; #define BLOCK_REG_PADDING(MODE, TYPE, FIRST) \ (!(FIRST) ? upward : FUNCTION_ARG_PADDING (MODE, TYPE)) -/* __throw will restore its own return address to be the same as the - return address of the function that the throw is being made to. - This is unfortunate, because we want to check the original - return address to see if we need to restore the TOC. - So we have to squirrel it away with this. */ -#define SETUP_FRAME_ADDRESSES() \ - do { if (TARGET_64BIT) rs6000_aix_emit_builtin_unwind_init (); } while (0) - /* Override svr4.h */ #undef MD_EXEC_PREFIX #undef MD_STARTFILE_PREFIX Index: gcc/config/rs6000/rs6000-protos.h =================================================================== --- gcc/config/rs6000/rs6000-protos.h (revision 164644) +++ gcc/config/rs6000/rs6000-protos.h (working copy) @@ -163,7 +163,6 @@ extern int rs6000_trampoline_size (void) extern alias_set_type get_TOC_alias_set (void); extern void rs6000_emit_prologue (void); extern void rs6000_emit_load_toc_table (int); -extern void rs6000_aix_emit_builtin_unwind_init (void); extern unsigned int rs6000_dbx_register_number (unsigned int); extern void rs6000_emit_epilogue (int); extern void rs6000_emit_eh_reg_restore (rtx, rtx); Index: gcc/config/rs6000/rs6000.c =================================================================== --- gcc/config/rs6000/rs6000.c (revision 164644) +++ gcc/config/rs6000/rs6000.c (working copy) @@ -18916,42 +18924,6 @@ rs6000_aix_asm_output_dwarf_table_ref (c fprintf (asm_out_file, "\t.ref %s\n", TARGET_STRIP_NAME_ENCODING (frame_table_label)); } - -/* If _Unwind_* has been called from within the same module, - toc register is not guaranteed to be saved to 40(1) on function - entry. Save it there in that case. */ - -void -rs6000_aix_emit_builtin_unwind_init (void) -{ - rtx mem; - rtx stack_top = gen_reg_rtx (Pmode); - rtx opcode_addr = gen_reg_rtx (Pmode); - rtx opcode = gen_reg_rtx (SImode); - rtx tocompare = gen_reg_rtx (SImode); - rtx no_toc_save_needed = gen_label_rtx (); - - mem = gen_frame_mem (Pmode, hard_frame_pointer_rtx); - emit_move_insn (stack_top, mem); - - mem = gen_frame_mem (Pmode, - gen_rtx_PLUS (Pmode, stack_top, - GEN_INT (2 * GET_MODE_SIZE (Pmode)))); - emit_move_insn (opcode_addr, mem); - emit_move_insn (opcode, gen_rtx_MEM (SImode, opcode_addr)); - emit_move_insn (tocompare, gen_int_mode (TARGET_32BIT ? 0x80410014 - : 0xE8410028, SImode)); - - do_compare_rtx_and_jump (opcode, tocompare, EQ, 1, - SImode, NULL_RTX, NULL_RTX, - no_toc_save_needed, -1); - - mem = gen_frame_mem (Pmode, - gen_rtx_PLUS (Pmode, stack_top, - GEN_INT (5 * GET_MODE_SIZE (Pmode)))); - emit_move_insn (mem, gen_rtx_REG (Pmode, 2)); - emit_label (no_toc_save_needed); -} /* This ties together stack memory (MEM with an alias set of frame_alias_set) and the change to the stack pointer. */ @@ -20237,22 +20209,6 @@ rs6000_emit_prologue (void) { unsigned int i, regno; - /* In AIX ABI we need to pretend we save r2 here. */ - if (TARGET_AIX) - { - rtx addr, reg, mem; - - reg = gen_rtx_REG (reg_mode, 2); - addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, - GEN_INT (sp_offset + 5 * reg_size)); - mem = gen_frame_mem (reg_mode, addr); - - insn = emit_move_insn (mem, reg); - rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, - NULL_RTX, NULL_RTX); - PATTERN (insn) = gen_blockage (); - } - for (i = 0; ; ++i) { regno = EH_RETURN_DATA_REGNO (i); @@ -20266,6 +20222,53 @@ rs6000_emit_prologue (void) } } + /* In AIX ABI we need to make sure r2 is really saved. */ + if (TARGET_AIX && crtl->calls_eh_return) + { + rtx tmp_reg, tmp_reg_si, compare_result, toc_save_done, jump; + long toc_restore_insn; + + gcc_assert (frame_reg_rtx == frame_ptr_rtx + || frame_reg_rtx == sp_reg_rtx); + tmp_reg = gen_rtx_REG (Pmode, 11); + tmp_reg_si = gen_rtx_REG (SImode, 11); + if (using_static_chain_p) + emit_move_insn (gen_rtx_REG (Pmode, 0), tmp_reg); + gcc_assert (saving_GPRs_inline && saving_FPRs_inline); + emit_move_insn (tmp_reg, gen_rtx_REG (Pmode, LR_REGNO)); + /* Peek at instruction to which this function returns. If it's + restoring r2, then we know we've already saved r2. We can't + unconditionally save r2 because the value we have will already + be updated if we arrived at this function via a plt call or + toc adjusting stub. */ + emit_move_insn (tmp_reg_si, gen_rtx_MEM (SImode, tmp_reg)); + toc_restore_insn = ((TARGET_32BIT ? 0x80410014 : 0xE8410028) + ^ 0x80000000) - 0x80000000; + emit_insn (gen_xorsi3 (tmp_reg_si, tmp_reg_si, + GEN_INT (toc_restore_insn & ~0xffff))); + compare_result = gen_rtx_REG (CCUNSmode, CR0_REGNO); + validate_condition_mode (EQ, CCUNSmode); + emit_insn (gen_rtx_SET (VOIDmode, compare_result, + gen_rtx_COMPARE (CCUNSmode, tmp_reg_si, + GEN_INT (toc_restore_insn + & 0xffff)))); + toc_save_done = gen_label_rtx (); + jump = gen_rtx_IF_THEN_ELSE (VOIDmode, + gen_rtx_EQ (VOIDmode, compare_result, + const0_rtx), + gen_rtx_LABEL_REF (VOIDmode, toc_save_done), + pc_rtx); + jump = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, jump)); + JUMP_LABEL (jump) = toc_save_done; + LABEL_NUSES (toc_save_done) += 1; + + emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, 2, + sp_offset + 5 * reg_size, info->total_size); + emit_label (toc_save_done); + if (using_static_chain_p) + emit_move_insn (tmp_reg, gen_rtx_REG (Pmode, 0)); + } + /* Save CR if we use any that must be preserved. */ if (!WORLD_SAVE_P (info) && info->cr_save_p) {