From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 21671 invoked by alias); 28 Aug 2009 09:50:55 -0000 Received: (qmail 21660 invoked by uid 22791); 28 Aug 2009 09:50:53 -0000 X-SWARE-Spam-Status: No, hits=-2.4 required=5.0 tests=AWL,BAYES_00 X-Spam-Check-By: sourceware.org Received: from mel.act-europe.fr (HELO mel.act-europe.fr) (212.99.106.210) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 28 Aug 2009 09:50:47 +0000 Received: from localhost (localhost [127.0.0.1]) by filtered-smtp.eu.adacore.com (Postfix) with ESMTP id 327512900E6; Fri, 28 Aug 2009 11:50:44 +0200 (CEST) Received: from mel.act-europe.fr ([127.0.0.1]) by localhost (smtp.eu.adacore.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id wk0mWp99BGyk; Fri, 28 Aug 2009 11:50:43 +0200 (CEST) Received: from cardhu.act-europe.fr (cardhu.act-europe.fr [10.10.0.168]) by mel.act-europe.fr (Postfix) with ESMTP id 0C7C82900FB; Fri, 28 Aug 2009 11:50:43 +0200 (CEST) Received: by cardhu.act-europe.fr (Postfix, from userid 546) id 017BA1D3; Fri, 28 Aug 2009 11:50:42 +0200 (CEST) Date: Fri, 28 Aug 2009 19:15:00 -0000 From: Olivier Hainque To: Joel Sherrill Cc: Geert Bosch , GCC Development , hainque@adacore.com Subject: Re: Anyone else run ACATS on ARM? Message-ID: <20090828095042.GA28441@cardhu.act-europe.fr> References: <4A82D295.4030907@oarcorp.com> <4B98FF9B-6C3A-4DD1-9C9F-72139E0EEC5B@adacore.com> <4A967362.4080203@oarcorp.com> <4A96871E.7050607@oarcorp.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="UlVJffcvxoiEqYs2" Content-Disposition: inline In-Reply-To: <4A96871E.7050607@oarcorp.com> User-Agent: Mutt/1.4.1i X-IsSubscribed: yes Mailing-List: contact gcc-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-owner@gcc.gnu.org X-SW-Source: 2009-08/txt/msg00525.txt.bz2 --UlVJffcvxoiEqYs2 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 1121 Hi Joel, Joel Sherrill wrote: > I can't seem to find the patch. Do you have a link? The initial submission, with a description of the problem we were having, is at http://gcc.gnu.org/ml/gcc-patches/2008-01/msg00759.html We have been using a slightly adjusted version for our gcc 4.3 based line of products, attached. I'm not clear on the status on mainline (whether the issue is still present etc). Olivier * config/arm/arm.c (args_to_rsa_distance): New function. Distance between the arguments and the registers save area. (arm_get_frame_offsets): Account for this distance in the frame pointer and registers save area offset computations. Add comments. (arm_expand_prologue): Add comments on the ARM frame pointer computation scheme. Count the "ip" push in the amount of space we use to save registers past the arguments area. Tidy the circuitry to restore IP past the frame pointer setup. (arm_compute_initial_elimination_offset) : Rewrite expressions along the lines of a straight common pattern. --UlVJffcvxoiEqYs2 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="arm-dword_align.dif" Content-length: 15092 *** ./gcc/config/arm/arm.c.ori Wed Feb 11 17:05:47 2009 --- ./gcc/config/arm/arm.c Fri Feb 13 12:23:39 2009 *************** void (*arm_lang_output_object_attributes *** 63,68 **** --- 63,69 ---- /* Forward function declarations. */ static arm_stack_offsets *arm_get_frame_offsets (void); + static int arm_args_to_rsa_distance (void); static void arm_add_gc_roots (void); static int arm_gen_constant (enum rtx_code, enum machine_mode, rtx, HOST_WIDE_INT, rtx, rtx, int, int); *************** arm_get_frame_offsets (void) *** 11941,11946 **** --- 11942,11950 ---- int saved; HOST_WIDE_INT frame_size; + /* Space between the arguments and the register save areas. */ + int args_to_rsa_distance = arm_args_to_rsa_distance (); + offsets = &cfun->machine->stack_offsets; /* We need to know if we are a leaf function. Unfortunately, it *************** arm_get_frame_offsets (void) *** 11962,11973 **** leaf = leaf_function_p (); ! /* Space for variadic functions. */ offsets->saved_args = current_function_pretend_args_size; ! ! /* In Thumb mode this is incorrect, but never used. */ ! offsets->frame = offsets->saved_args + (frame_pointer_needed ? 4 : 0); ! if (TARGET_32BIT) { unsigned int regno; --- 11966,11976 ---- leaf = leaf_function_p (); ! /* Offset from entry-sp to the bottommost slot of the arguments area, ! possibly including varargs saved by this function in its own frame. */ offsets->saved_args = current_function_pretend_args_size; ! ! /* Space for saved registers. */ if (TARGET_32BIT) { unsigned int regno; *************** arm_get_frame_offsets (void) *** 12008,12016 **** saved += 16; } ! /* Saved registers include the stack frame. */ ! offsets->saved_regs = offsets->saved_args + saved; offsets->soft_frame = offsets->saved_regs + CALLER_INTERWORKING_SLOT_SIZE; /* A leaf function does not need any stack alignment if it has nothing on the stack. */ if (leaf && frame_size == 0) --- 12011,12032 ---- saved += 16; } ! /* Now, other from entry-sp offset computations, accounting for a possible ! whole between the saved-arguments and saved-registers areas. */ ! ! /* Offset to the bottommost slot in the registers save area. */ ! offsets->saved_regs = offsets->saved_args + args_to_rsa_distance + saved; ! ! /* Offset to hard frame pointer. On ARM, topmost slot in the registers ! sava area. This would be different on THUMB but is never used. */ ! offsets->frame ! = (offsets->saved_args + args_to_rsa_distance ! + (frame_pointer_needed ? 4 : 0)); ! ! /* Offset to soft frame pointer, slot just above the locals area, past ! room for a possible interworking slot and alignment padding. */ offsets->soft_frame = offsets->saved_regs + CALLER_INTERWORKING_SLOT_SIZE; + /* A leaf function does not need any stack alignment if it has nothing on the stack. */ if (leaf && frame_size == 0) *************** arm_get_frame_offsets (void) *** 12025,12031 **** --- 12041,12051 ---- && (offsets->soft_frame & 7)) offsets->soft_frame += 4; + /* Offset to bottommost slot for local variables ... */ offsets->locals_base = offsets->soft_frame + frame_size; + + /* ... and for outgoing arguments, bottom of the whole stack frame for + this function, hence also subject to possible alignment padding. */ offsets->outgoing_args = (offsets->locals_base + current_function_outgoing_args_size); *************** arm_compute_initial_elimination_offset ( *** 12058,12087 **** switch (from) { case ARG_POINTER_REGNUM: switch (to) { case THUMB_HARD_FRAME_POINTER_REGNUM: return 0; case FRAME_POINTER_REGNUM: ! /* This is the reverse of the soft frame pointer ! to hard frame pointer elimination below. */ ! return offsets->soft_frame - offsets->saved_args; case ARM_HARD_FRAME_POINTER_REGNUM: ! /* If there is no stack frame then the hard ! frame pointer and the arg pointer coincide. */ ! if (offsets->frame == offsets->saved_regs) ! return 0; ! /* FIXME: Not sure about this. Maybe we should always return 0 ? */ ! return (frame_pointer_needed ! && cfun->static_chain_decl != NULL ! && ! cfun->machine->uses_anonymous_args) ? 4 : 0; case STACK_POINTER_REGNUM: ! /* If nothing has been pushed on the stack at all ! then this will return -4. This *is* correct! */ ! return offsets->outgoing_args - (offsets->saved_args + 4); default: gcc_unreachable (); --- 12078,12103 ---- switch (from) { case ARG_POINTER_REGNUM: + /* We use offsets->saved_args as a reference offset to the actual + arguments area then adjust by the difference with what the arg + pointer designates. */ + switch (to) { case THUMB_HARD_FRAME_POINTER_REGNUM: return 0; case FRAME_POINTER_REGNUM: ! return (offsets->soft_frame - offsets->saved_args ! - FIRST_PARM_OFFSET (current_function_decl)); case ARM_HARD_FRAME_POINTER_REGNUM: ! return (offsets->frame - offsets->saved_args ! - FIRST_PARM_OFFSET (current_function_decl)); case STACK_POINTER_REGNUM: ! return (offsets->outgoing_args - offsets->saved_args ! - FIRST_PARM_OFFSET (current_function_decl)); default: gcc_unreachable (); *************** thumb_set_frame_pointer (arm_stack_offse *** 12242,12247 **** --- 12258,12280 ---- RTX_FRAME_RELATED_P (insn) = 1; } + /* How many bytes the prologue expansion pushes between the arguments and + the registers save area. */ + static int + arm_args_to_rsa_distance (void) + { + int distance = 0; + + /* Account for our possible push of the input static chain. */ + if (TARGET_ARM && frame_pointer_needed + && IS_NESTED (arm_current_func_type ()) + && df_regs_ever_live_p(3) != 0 + && current_function_pretend_args_size == 0) + distance += 4; + + return distance; + } + /* Generate the prologue instructions for entry into an ARM or Thumb-2 function. */ void *************** arm_expand_prologue (void) *** 12252,12263 **** rtx ip_rtx; unsigned long live_regs_mask; unsigned long func_type; - int fp_offset = 0; - int saved_pretend_args = 0; int saved_regs = 0; unsigned HOST_WIDE_INT args_to_push; arm_stack_offsets *offsets; func_type = arm_current_func_type (); /* Naked functions don't have prologues. */ --- 12285,12314 ---- rtx ip_rtx; unsigned long live_regs_mask; unsigned long func_type; int saved_regs = 0; unsigned HOST_WIDE_INT args_to_push; arm_stack_offsets *offsets; + /* When we setup the ARM frame pointer, we have it designate the topmost + entry in the registers save with a number of devices: + - We use the IP register as a temporary scratch location to hold + the entry sp, + - We keep track of the amount of data we push before the registers + save area, and + - We arrange to save/restore the initial value of the IP register when + this is required for proper functional behavior later on. */ + + /* Amount of data between the entry-sp and the ARM frame pointer. */ + int fp_offset = 0; + + /* When IP's original value is to be restored from a register, this + is the register number. */ + unsigned orip_regno = INVALID_REGNUM; + + /* When IP's original value is to be restored from a stack slot off + the entry stack pointer, this is the slot offset. */ + int orip_sp_offset = -1; + func_type = arm_current_func_type (); /* Naked functions don't have prologues. */ *************** arm_expand_prologue (void) *** 12303,12315 **** emit_insn (gen_movsi (stack_pointer_rtx, r1)); } if (frame_pointer_needed && TARGET_ARM) { if (IS_INTERRUPT (func_type)) { /* Interrupt functions must not corrupt any registers. Creating a frame pointer however, corrupts the IP ! register, so we must push it first. */ insn = emit_multi_reg_push (1 << IP_REGNUM); /* Do not set RTX_FRAME_RELATED_P on this insn. --- 12354,12371 ---- emit_insn (gen_movsi (stack_pointer_rtx, r1)); } + /* Setup IP for later frame pointer computation purposes, with special + pre-processing when IP couldn't just be clobbered carelessly. */ + if (frame_pointer_needed && TARGET_ARM) { if (IS_INTERRUPT (func_type)) { /* Interrupt functions must not corrupt any registers. Creating a frame pointer however, corrupts the IP ! register, so we must push it first. This value will ! be restored by the epilogue, hence is conceptually part ! of the register save area. */ insn = emit_multi_reg_push (1 << IP_REGNUM); /* Do not set RTX_FRAME_RELATED_P on this insn. *************** arm_expand_prologue (void) *** 12344,12362 **** inherited from the caller. */ if (df_regs_ever_live_p (3) == false) ! insn = emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx); else if (args_to_push == 0) { rtx dwarf; insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx); insn = emit_set_insn (gen_frame_mem (SImode, insn), ip_rtx); ! fp_offset = 4; /* Just tell the dwarf backend that we adjusted SP. */ dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx, ! plus_constant (stack_pointer_rtx, ! -fp_offset)); RTX_FRAME_RELATED_P (insn) = 1; REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf, REG_NOTES (insn)); --- 12400,12433 ---- inherited from the caller. */ if (df_regs_ever_live_p (3) == false) ! { ! insn = emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx); ! orip_regno = 3; ! } else if (args_to_push == 0) { rtx dwarf; insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx); insn = emit_set_insn (gen_frame_mem (SImode, insn), ip_rtx); ! ! /* This push doesn't account as a regular register save in the ! save_reg_mask sense, so shifts the "frame" location. */ ! fp_offset += 4; ! ! /* Tell IP is to be restored from the slot where we just ! pushed it. We assume fp_offset conveys the number of ! bytes pushed up to now. */ ! orip_sp_offset = fp_offset; ! ! /* We need to account for the space it takes, still, and ! note that IP will have to be restored from there. */ ! saved_regs += 4; /* Just tell the dwarf backend that we adjusted SP. */ dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx, ! plus_constant (stack_pointer_rtx, -4)); ! RTX_FRAME_RELATED_P (insn) = 1; REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf, REG_NOTES (insn)); *************** arm_expand_prologue (void) *** 12374,12388 **** RTX_FRAME_RELATED_P (insn) = 1; ! saved_pretend_args = 1; ! fp_offset = args_to_push; args_to_push = 0; /* Now reuse r3 to preserve IP. */ emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx); } } insn = emit_set_insn (ip_rtx, plus_constant (stack_pointer_rtx, fp_offset)); RTX_FRAME_RELATED_P (insn) = 1; --- 12445,12460 ---- RTX_FRAME_RELATED_P (insn) = 1; ! fp_offset += args_to_push; args_to_push = 0; /* Now reuse r3 to preserve IP. */ emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx); + orip_regno = 3; } } + /* Here, we setup IP to designate the entry stack pointer. */ insn = emit_set_insn (ip_rtx, plus_constant (stack_pointer_rtx, fp_offset)); RTX_FRAME_RELATED_P (insn) = 1; *************** arm_expand_prologue (void) *** 12399,12404 **** --- 12471,12479 ---- (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (- args_to_push))); RTX_FRAME_RELATED_P (insn) = 1; + + fp_offset += args_to_push; + args_to_push = 0; } /* If this is an interrupt service routine, and the link register *************** arm_expand_prologue (void) *** 12416,12421 **** --- 12491,12497 ---- emit_set_insn (lr, plus_constant (lr, -4)); } + /* Now we emit the registers save operations ... */ if (live_regs_mask) { insn = emit_multi_reg_push (live_regs_mask); *************** arm_expand_prologue (void) *** 12426,12457 **** if (! IS_VOLATILE (func_type)) saved_regs += arm_save_coproc_regs (); if (frame_pointer_needed && TARGET_ARM) { ! /* Create the new frame pointer. */ ! { ! insn = GEN_INT (-(4 + args_to_push + fp_offset)); ! insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, ip_rtx, insn)); ! RTX_FRAME_RELATED_P (insn) = 1; ! if (IS_NESTED (func_type)) ! { ! /* Recover the static chain register. */ ! if (!df_regs_ever_live_p (3) ! || saved_pretend_args) ! insn = gen_rtx_REG (SImode, 3); ! else /* if (current_function_pretend_args_size == 0) */ ! { ! insn = plus_constant (hard_frame_pointer_rtx, 4); ! insn = gen_frame_mem (SImode, insn); ! } ! emit_set_insn (ip_rtx, insn); ! /* Add a USE to stop propagate_one_insn() from barfing. */ ! emit_insn (gen_prologue_use (ip_rtx)); ! } } } offsets = arm_get_frame_offsets (); if (offsets->outgoing_args != offsets->saved_args + saved_regs) { --- 12502,12537 ---- if (! IS_VOLATILE (func_type)) saved_regs += arm_save_coproc_regs (); + /* ... then create the ARM frame pointer and restore the initial IP + register value if need be. */ if (frame_pointer_needed && TARGET_ARM) { ! /* At this point, we have IP setup to designate the entry sp and ! fp_offset conveys the amount of bytes we pushed before the register ! saves. Setup the frame pointer from there: */ ! insn = GEN_INT (-(4 + fp_offset)); ! insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, ip_rtx, insn)); ! RTX_FRAME_RELATED_P (insn) = 1; ! /* Then restore IP from the indication of where it was saved ! for this purpose. */ ! if (orip_regno != INVALID_REGNUM) ! insn = gen_rtx_REG (SImode, orip_regno); ! else if (orip_sp_offset != -1) ! insn = gen_frame_mem ! (SImode, plus_constant (ip_rtx, -orip_sp_offset)); ! else ! insn = NULL_RTX; ! ! if (insn != NULL_RTX) ! { ! emit_set_insn (ip_rtx, insn); ! /* Add a USE to stop propagate_one_insn() from barfing. */ ! emit_insn (gen_prologue_use (ip_rtx)); } } + /* Now allocate room for locals and outgoing args. */ offsets = arm_get_frame_offsets (); if (offsets->outgoing_args != offsets->saved_args + saved_regs) { --UlVJffcvxoiEqYs2--