From patchwork Thu May 31 13:58:13 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Greta Yorsh X-Patchwork-Id: 162164 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 0F508B6FA4 for ; Thu, 31 May 2012 23:59:17 +1000 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1339077558; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: From:To:References:In-Reply-To:Subject:Date:Message-ID: MIME-Version:Content-Type:Mailing-List:Precedence:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:Sender: Delivered-To; bh=b1Yb4FgIZdfjNVWJFhOP8sr00Ak=; b=PvJU+dCjhSSfc/N NxK+XnR0iMbTEF42/SAzIJmzR9eIKClrSFmJqxeNkHIdMp9fbCc/og64u6Kn56+x jwoSXbngLAntgHs4pq3Ny9cvPwiwQIiEZLz6r+iT5fNe0gMtCEVZnel72YG2bnoP +YB1CCeUYdcyNyHnQ9r15q0cnDzY= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:From:To:References:In-Reply-To:Subject:Date:Message-ID:MIME-Version:X-MC-Unique:Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=cKEm5YKSp3v2evbVu3wqhJE/YMJeca+j62zVb3yOsDk7o+tCRoJQP9TS8A/90a lXcjRz2Q+mYla+5sjIS3UYy/lxTYrBHy5ZwoSqoEVsT2UF7Kniiq1dg77WrvLJTE oMUBde0bd++i5hCMZ0kfXCEk4OMtszymnfGvputBj/51o=; Received: (qmail 1888 invoked by alias); 31 May 2012 13:59:12 -0000 Received: (qmail 1866 invoked by uid 22791); 31 May 2012 13:59:10 -0000 X-SWARE-Spam-Status: No, hits=-2.7 required=5.0 tests=AWL, BAYES_00, KHOP_RCVD_UNTRUST, KHOP_THREADED, MSGID_MULTIPLE_AT, RCVD_IN_DNSWL_LOW, RCVD_IN_HOSTKARMA_NO, TW_DM, TW_LR X-Spam-Check-By: sourceware.org Received: from service87.mimecast.com (HELO service87.mimecast.com) (91.220.42.44) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 31 May 2012 13:58:56 +0000 Received: from cam-owa2.Emea.Arm.com (fw-tnat.cambridge.arm.com [217.140.96.21]) by service87.mimecast.com; Thu, 31 May 2012 14:58:14 +0100 Received: from E103079 ([10.1.255.212]) by cam-owa2.Emea.Arm.com with Microsoft SMTPSVC(6.0.3790.3959); Thu, 31 May 2012 14:58:16 +0100 From: "Greta Yorsh" To: "GCC Patches" References: <000001cd3f33$5b5c25a0$121470e0$@Yorsh@arm.com> In-Reply-To: <000001cd3f33$5b5c25a0$121470e0$@Yorsh@arm.com> Subject: [Patch, ARM][4/8] Epilogue in RTL: expand epilogue for apcs frame Date: Thu, 31 May 2012 14:58:13 +0100 Message-ID: <000e01cd3f35$6bf83e60$43e8bb20$@Yorsh@arm.com> MIME-Version: 1.0 X-MC-Unique: 112053114581434501 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 Helper function for epilogue expansion. Emit RTL for APCS frame epilogue (when -mapcs-frame command line option is specified). This function is used by a later patch. For APCS frame epilogue, the compiler currently generates LDM with SP as both the base register and one of the destination registers. For example: @ APCS_FRAME epilogue ldmfd sp, {r4, fp, sp, pc} @ non-APCS_FRAME epilogue ldmfd sp!, {r4, fp, pc} The use of SP in LDM register list is deprecated, but this patch does not address the problem. To generate the epilogue for APCS frame in RTL, this patch adds a new alternative to arm_addsi2 insn in ARM mode only to generate "sub sp, fp, #imm". Previously, there was no pattern to generate sub with SP as the destination register and not SP as the operand register. ChangeLog: gcc 2012-05-31 Ian Bolton Sameera Deshpande Greta Yorsh * config/arm/arm.c (arm_expand_epilogue_apcs_frame): New function. * config/arm/arm.md (arm_addsi3) Add an alternative. diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 491ffea..d6b4c2e 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -22896,6 +22896,232 @@ thumb1_expand_epilogue (void) emit_use (gen_rtx_REG (SImode, LR_REGNUM)); } +/* Epilogue code for APCS frame. */ +static void +arm_expand_epilogue_apcs_frame (bool really_return) +{ + unsigned long func_type; + unsigned long saved_regs_mask; + int num_regs = 0; + int i; + int floats_from_frame = 0; + arm_stack_offsets *offsets; + + gcc_assert (TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM); + func_type = arm_current_func_type (); + + /* Get frame offsets for ARM. */ + offsets = arm_get_frame_offsets (); + saved_regs_mask = offsets->saved_regs_mask; + + /* Find the offset of the floating-point save area in the frame. */ + floats_from_frame = offsets->saved_args - offsets->frame; + + /* Compute how many core registers saved and how far away the floats are. */ + for (i = 0; i <= LAST_ARM_REGNUM; i++) + if (saved_regs_mask & (1 << i)) + { + num_regs++; + floats_from_frame += 4; + } + + if (TARGET_HARD_FLOAT && TARGET_VFP) + { + int start_reg; + + /* The offset is from IP_REGNUM. */ + int saved_size = arm_get_vfp_saved_size (); + if (saved_size > 0) + { + floats_from_frame += saved_size; + emit_insn (gen_addsi3 (gen_rtx_REG (SImode, IP_REGNUM), + hard_frame_pointer_rtx, + GEN_INT (-floats_from_frame))); + } + + /* Generate VFP register multi-pop. */ + start_reg = FIRST_VFP_REGNUM; + + for (i = FIRST_VFP_REGNUM; i < LAST_VFP_REGNUM; i += 2) + /* Look for a case where a reg does not need restoring. */ + if ((!df_regs_ever_live_p (i) || call_used_regs[i]) + && (!df_regs_ever_live_p (i + 1) + || call_used_regs[i + 1])) + { + if (start_reg != i) + arm_emit_vfp_multi_reg_pop (start_reg, + (i - start_reg) / 2, + gen_rtx_REG (SImode, + IP_REGNUM)); + start_reg = i + 2; + } + + /* Restore the remaining regs that we have discovered (or possibly + even all of them, if the conditional in the for loop never + fired). */ + if (start_reg != i) + arm_emit_vfp_multi_reg_pop (start_reg, + (i - start_reg) / 2, + gen_rtx_REG (SImode, IP_REGNUM)); + } + else if (TARGET_FPA_EMU2) + { + for (i = LAST_FPA_REGNUM; i >= FIRST_FPA_REGNUM; i--) + if (df_regs_ever_live_p (i) && !call_used_regs[i]) + { + rtx addr; + rtx insn; + floats_from_frame += 12; + addr = gen_rtx_MEM (XFmode, + gen_rtx_PLUS (SImode, + hard_frame_pointer_rtx, + GEN_INT (- floats_from_frame))); + set_mem_alias_set (addr, get_frame_alias_set ()); + insn = emit_insn (gen_rtx_SET (XFmode, + gen_rtx_REG (XFmode, i), + addr)); + REG_NOTES (insn) = alloc_reg_note (REG_CFA_RESTORE, + gen_rtx_REG (XFmode, i), + NULL_RTX); + } + } + else + { + int idx = 0; + rtx load_seq[4]; + rtx dwarf = NULL_RTX; + rtx par; + rtx frame_mem; + + for (i = LAST_FPA_REGNUM; i >= FIRST_FPA_REGNUM; i--) + { + /* We can't unstack more than four registers at once. */ + if (idx == 4) + { + par = emit_insn (gen_rtx_PARALLEL (VOIDmode, + gen_rtvec_v (idx, load_seq))); + REG_NOTES (par) = dwarf; + dwarf = NULL_RTX; + idx = 0; + } + + if (df_regs_ever_live_p (i) && !call_used_regs[i]) + { + floats_from_frame += 12; + + frame_mem = gen_frame_mem (XFmode, + plus_constant (hard_frame_pointer_rtx, + - floats_from_frame)); + load_seq[idx] = gen_rtx_SET (VOIDmode, gen_rtx_REG (XFmode, i), + frame_mem); + dwarf = alloc_reg_note (REG_CFA_RESTORE, gen_rtx_REG (XFmode, i), + dwarf); + idx++; + } + else if (idx) + { + /* Registers must be consecutive. */ + par = emit_insn (gen_rtx_PARALLEL (VOIDmode, + gen_rtvec_v (idx, load_seq))); + REG_NOTES (par) = dwarf; + dwarf = NULL_RTX; + idx = 0; + } + } + + /* Pop the last registers. */ + if (idx) + { + par = emit_insn (gen_rtx_PARALLEL (VOIDmode, + gen_rtvec_v (idx, load_seq))); + REG_NOTES (par) = dwarf; + } + } + + if (TARGET_IWMMXT) + { + /* The frame pointer is guaranteed to be non-double-word aligned, as + it is set to double-word-aligned old_stack_pointer - 4. */ + rtx insn; + int lrm_count = (num_regs % 2) ? (num_regs + 2) : (num_regs + 1); + + for (i = LAST_IWMMXT_REGNUM; i >= FIRST_IWMMXT_REGNUM; i--) + if (df_regs_ever_live_p (i) && !call_used_regs[i]) + { + rtx addr = gen_frame_mem (V2SImode, + plus_constant (hard_frame_pointer_rtx, + - lrm_count * 4)); + insn = emit_insn (gen_movsi (gen_rtx_REG (V2SImode, i), addr)); + REG_NOTES (insn) = alloc_reg_note (REG_CFA_RESTORE, + gen_rtx_REG (V2SImode, i), + NULL_RTX); + lrm_count += 2; + } + } + + /* saved_regs_mask should contain IP which contains old stack pointer + at the time of activation creation. Since SP and IP are adjacent registers, + we can restore the value directly into SP. */ + gcc_assert (saved_regs_mask & (1 << IP_REGNUM)); + saved_regs_mask &= ~(1 << IP_REGNUM); + saved_regs_mask |= (1 << SP_REGNUM); + + /* There are two registers left in saved_regs_mask - LR and PC. We + only need to restore LR (the return address), but to + save time we can load it directly into PC, unless we need a + special function exit sequence, or we are not really returning. */ + if (really_return + && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL + && !crtl->calls_eh_return) + /* Delete LR from the register mask, so that LR on + the stack is loaded into the PC in the register mask. */ + saved_regs_mask &= ~(1 << LR_REGNUM); + else + saved_regs_mask &= ~(1 << PC_REGNUM); + + num_regs = bit_count (saved_regs_mask); + if ((offsets->outgoing_args != (1 + num_regs)) || cfun->calls_alloca) + { + /* Unwind the stack to just below the saved registers. */ + emit_insn (gen_addsi3 (stack_pointer_rtx, + hard_frame_pointer_rtx, + GEN_INT (- 4 * num_regs))); + } + + arm_emit_multi_reg_pop (saved_regs_mask); + + if (IS_INTERRUPT (func_type)) + { + /* Interrupt handlers will have pushed the + IP onto the stack, so restore it now. */ + rtx insn; + rtx addr = gen_rtx_MEM (SImode, + gen_rtx_POST_INC (SImode, + stack_pointer_rtx)); + set_mem_alias_set (addr, get_frame_alias_set ()); + insn = emit_insn (gen_movsi (gen_rtx_REG (SImode, IP_REGNUM), addr)); + REG_NOTES (insn) = alloc_reg_note (REG_CFA_RESTORE, + gen_rtx_REG (SImode, IP_REGNUM), + NULL_RTX); + } + + if (!really_return || (saved_regs_mask & (1 << PC_REGNUM))) + return; + + if (crtl->calls_eh_return) + emit_insn (gen_addsi3 (stack_pointer_rtx, + stack_pointer_rtx, + GEN_INT (ARM_EH_STACKADJ_REGNUM))); + + if (IS_STACKALIGN (func_type)) + /* Restore the original stack pointer. Before prologue, the stack was + realigned and the original stack pointer saved in r0. For details, + see comment in arm_expand_prologue. */ + emit_insn (gen_movsi (stack_pointer_rtx, gen_rtx_REG (SImode, 0))); + + emit_jump_insn (simple_return_rtx); +} + /* Implementation of insn prologue_thumb1_interwork. This is the first "instruction" of a function called in ARM mode. Swap to thumb mode. */ diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 98387fa..3a237c8 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -718,9 +718,9 @@ ;; (plus (reg rN) (reg sp)) into (reg rN). In this case reload will ;; put the duplicated register first, and not try the commutative version. (define_insn_and_split "*arm_addsi3" - [(set (match_operand:SI 0 "s_register_operand" "=r, k,r,r, k, r, k,r, k, r") - (plus:SI (match_operand:SI 1 "s_register_operand" "%rk,k,r,rk,k, rk,k,rk,k, rk") - (match_operand:SI 2 "reg_or_int_operand" "rI,rI,k,Pj,Pj,L, L,PJ,PJ,?n")))] + [(set (match_operand:SI 0 "s_register_operand" "=r, k,r,r, k, r, k,k,r, k, r") + (plus:SI (match_operand:SI 1 "s_register_operand" "%rk,k,r,rk,k, rk,k,r,rk,k, rk") + (match_operand:SI 2 "reg_or_int_operand" "rI,rI,k,Pj,Pj,L, L,L,PJ,PJ,?n")))] "TARGET_32BIT" "@ add%?\\t%0, %1, %2 @@ -730,6 +730,7 @@ addw%?\\t%0, %1, %2 sub%?\\t%0, %1, #%n2 sub%?\\t%0, %1, #%n2 + sub%?\\t%0, %1, #%n2 subw%?\\t%0, %1, #%n2 subw%?\\t%0, %1, #%n2 #" @@ -744,9 +745,9 @@ operands[1], 0); DONE; " - [(set_attr "length" "4,4,4,4,4,4,4,4,4,16") + [(set_attr "length" "4,4,4,4,4,4,4,4,4,4,16") (set_attr "predicable" "yes") - (set_attr "arch" "*,*,*,t2,t2,*,*,t2,t2,*")] + (set_attr "arch" "*,*,*,t2,t2,*,*,a,t2,t2,*")] ) (define_insn_and_split "*thumb1_addsi3"