From patchwork Thu Jun 16 13:58:43 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 100642 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 B7CB0B6FB1 for ; Thu, 16 Jun 2011 23:59:15 +1000 (EST) Received: (qmail 31973 invoked by alias); 16 Jun 2011 13:59:08 -0000 Received: (qmail 31952 invoked by uid 22791); 16 Jun 2011 13:59:05 -0000 X-SWARE-Spam-Status: No, hits=-6.1 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, TW_YF, T_RP_MATCHES_RCVD 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, 16 Jun 2011 13:58:47 +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 p5GDwiwv023033 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Thu, 16 Jun 2011 09:58:44 -0400 Received: from anchor.twiddle.net (vpn-238-15.phx2.redhat.com [10.3.238.15]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p5GDwhqP004563; Thu, 16 Jun 2011 09:58:43 -0400 Message-ID: <4DFA0C13.9060102@redhat.com> Date: Thu, 16 Jun 2011 06:58:43 -0700 From: Richard Henderson User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.17) Gecko/20110428 Fedora/3.1.10-1.fc15 Thunderbird/3.1.10 MIME-Version: 1.0 To: Denis Chertykov CC: Georg-Johann Lay , gcc-patches@gcc.gnu.org, Anatoly Sokolov , "Eric B. Weddington" Subject: Re: [Patch, AVR]: Fix PR46779 References: <4DF0FAB5.6070704@gjlay.de> <4DF11D20.4030907@gjlay.de> <4DF1ED76.4030507@gjlay.de> <4DF650B7.3030705@gjlay.de> <4DF73490.2080709@gjlay.de> <4DF7D2B5.1090708@gjlay.de> <4DF8ED42.1030706@redhat.com> <4DF918A9.4070003@gjlay.de> <4DF92AEA.4000906@redhat.com> <4DF93B17.8020008@redhat.com> In-Reply-To: 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 On 06/16/2011 04:46 AM, Denis Chertykov wrote: > I forgot to said that suggestion from Bernd Schmidt about > HARD_FRAME_POINTER_REGNUM seems very useful: >> Maybe it would help for your port to define a separate >> FRAME_POINTER_REGNUM, able to hold an HImode value, which then gets >> eliminated to HARD_FRAME_POINTER_REGNUM? This mechanism is used on many >> other ports if you need examples. > > It's not related to addressing modes but it's related to frame pointer bugs. Yes, that was the first thing I did while investigating G-J's spill failure. It didn't help that, of course, but I kept it around in my tree anyway. This probably doesn't apply by itself, as is, but for the record... r~ commit 0ca9df0a8c2722e8a555c2c37d7d7b40467bc5d4 Author: Richard Henderson Date: Wed Jun 15 14:03:19 2011 -0700 avr: Add soft frame pointer register. * config/avr/avr.c (avr_can_eliminate): Simplify. (avr_initial_elimination_offset): Likewise. (expand_prologue): Use hard_frame_pointer_rtx. (expand_epilogue): Likewise. (avr_legitimize_address): Gut. (avr_hard_regno_nregs): New. (avr_hard_regno_ok): Allow only Pmode for arg and frame_pointers. (avr_regno_mode_code_ok_for_base_b): Handle arg and frame pointers. * config/avr/avr.h (FIXED_REGISTERS): Adjust arg pointer, add soft frame pointer. (CALL_USED_REGISTERS): Likewise. (REG_CLASS_CONTENTS): Likewise. (REGISTER_NAMES): Likewise. (HARD_REGNO_NREGS): Use avr_hard_regno_nregs. (HARD_FRAME_POINTER_REGNUM): New. (FRAME_POINTER_REGNUM): Use soft frame pointer. (ELIMINABLE_REGS): Eliminate from the soft frame pointer, remove the HARD_FRAME_POINTER self-elimination. diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h index 2af123c..5c60e2e 100644 --- a/gcc/config/avr/avr-protos.h +++ b/gcc/config/avr/avr-protos.h @@ -98,6 +98,7 @@ extern int byte_immediate_operand (rtx op, enum machine_mode mode); extern int test_hard_reg_class (enum reg_class rclass, rtx x); extern int jump_over_one_insn_p (rtx insn, rtx dest); +extern int avr_hard_regno_nregs (int regno, enum machine_mode mode); extern int avr_hard_regno_mode_ok (int regno, enum machine_mode mode); extern void final_prescan_insn (rtx insn, rtx *operand, int num_operands); extern int avr_simplify_comparison_p (enum machine_mode mode, diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index c6087fe..e1d6b50 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -493,29 +493,28 @@ avr_regs_to_save (HARD_REG_SET *set) /* Return true if register FROM can be eliminated via register TO. */ bool -avr_can_eliminate (const int from, const int to) +avr_can_eliminate (int from ATTRIBUTE_UNUSED, int to) { - return ((from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM) - || ((from == FRAME_POINTER_REGNUM - || from == FRAME_POINTER_REGNUM + 1) - && !frame_pointer_needed)); + return to == HARD_FRAME_POINTER_REGNUM; } /* Compute offset between arg_pointer and frame_pointer. */ int -avr_initial_elimination_offset (int from, int to) +avr_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED) { - if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) - return 0; - else - { - int offset = frame_pointer_needed ? 2 : 0; - int avr_pc_size = AVR_HAVE_EIJMP_EICALL ? 3 : 2; + int offset = 0; + if (from == ARG_POINTER_REGNUM) + { + offset += AVR_HAVE_EIJMP_EICALL ? 3 : 2; + offset += frame_pointer_needed ? 2 : 0; offset += avr_regs_to_save (NULL); - return get_frame_size () + (avr_pc_size) + 1 + offset; + offset += get_frame_size (); + offset += 1; /* post-dec stack space */ } + + return offset; } /* Actual start of frame is virtual_stack_vars_rtx this is offset from @@ -747,12 +746,12 @@ expand_prologue (void) notes to the front. Thus we build them in the reverse order of how we want dwarf2out to process them. */ - /* The function does always set frame_pointer_rtx, but whether that + /* The function does always set hard_frame_pointer_rtx, but whether that is going to be permanent in the function is frame_pointer_needed. */ add_reg_note (insn, REG_CFA_ADJUST_CFA, gen_rtx_SET (VOIDmode, (frame_pointer_needed - ? frame_pointer_rtx : stack_pointer_rtx), + ? hard_frame_pointer_rtx : stack_pointer_rtx), plus_constant (stack_pointer_rtx, -(size + live_seq)))); @@ -793,7 +792,7 @@ expand_prologue (void) if (!size) { - insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); + insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx); RTX_FRAME_RELATED_P (insn) = 1; } else @@ -816,12 +815,12 @@ expand_prologue (void) { /* The high byte (r29) doesn't change. Prefer 'subi' (1 cycle) over 'sbiw' (2 cycles, same size). */ - myfp = gen_rtx_REG (QImode, FRAME_POINTER_REGNUM); + myfp = gen_rtx_REG (QImode, HARD_FRAME_POINTER_REGNUM); } else { /* Normal sized addition. */ - myfp = frame_pointer_rtx; + myfp = hard_frame_pointer_rtx; } /* Method 1-Adjust frame pointer. */ @@ -833,12 +832,12 @@ expand_prologue (void) instead indicate that the entire operation is complete after the frame pointer subtraction is done. */ - emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); + emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx); insn = emit_move_insn (myfp, plus_constant (myfp, -size)); RTX_FRAME_RELATED_P (insn) = 1; add_reg_note (insn, REG_CFA_ADJUST_CFA, - gen_rtx_SET (VOIDmode, frame_pointer_rtx, + gen_rtx_SET (VOIDmode, hard_frame_pointer_rtx, plus_constant (stack_pointer_rtx, -size))); @@ -847,23 +846,23 @@ expand_prologue (void) need not be annotated at all. */ if (AVR_HAVE_8BIT_SP) { - emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); + emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx); } else if (TARGET_NO_INTERRUPTS || cfun->machine->is_signal || cfun->machine->is_OS_main) { emit_insn (gen_movhi_sp_r_irq_off (stack_pointer_rtx, - frame_pointer_rtx)); + hard_frame_pointer_rtx)); } else if (cfun->machine->is_interrupt) { emit_insn (gen_movhi_sp_r_irq_on (stack_pointer_rtx, - frame_pointer_rtx)); + hard_frame_pointer_rtx)); } else { - emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); + emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx); } fp_plus_insns = get_insns (); @@ -880,7 +879,7 @@ expand_prologue (void) insn = emit_move_insn (stack_pointer_rtx, insn); RTX_FRAME_RELATED_P (insn) = 1; - insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); + insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx); RTX_FRAME_RELATED_P (insn) = 1; sp_plus_insns = get_insns (); @@ -997,13 +996,13 @@ expand_epilogue (bool sibcall_p) if (frame_pointer_needed) { /* Get rid of frame. */ - emit_move_insn(frame_pointer_rtx, - gen_rtx_PLUS (HImode, frame_pointer_rtx, - gen_int_mode (size, HImode))); + emit_move_insn (hard_frame_pointer_rtx, + gen_rtx_PLUS (HImode, hard_frame_pointer_rtx, + gen_int_mode (size, HImode))); } else { - emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); + emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx); } emit_insn (gen_epilogue_restores (gen_int_mode (live_seq, HImode))); @@ -1022,12 +1021,12 @@ expand_epilogue (bool sibcall_p) { /* The high byte (r29) doesn't change - prefer 'subi' (1 cycle) over 'sbiw' (2 cycles, same size). */ - myfp = gen_rtx_REG (QImode, FRAME_POINTER_REGNUM); + myfp = gen_rtx_REG (QImode, HARD_FRAME_POINTER_REGNUM); } else { /* Normal sized addition. */ - myfp = frame_pointer_rtx; + myfp = hard_frame_pointer_rtx; } /* Method 1-Adjust frame pointer. */ @@ -1038,22 +1037,22 @@ expand_epilogue (bool sibcall_p) /* Copy to stack pointer. */ if (AVR_HAVE_8BIT_SP) { - emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); + emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx); } else if (TARGET_NO_INTERRUPTS || cfun->machine->is_signal) { emit_insn (gen_movhi_sp_r_irq_off (stack_pointer_rtx, - frame_pointer_rtx)); + hard_frame_pointer_rtx)); } else if (cfun->machine->is_interrupt) { emit_insn (gen_movhi_sp_r_irq_on (stack_pointer_rtx, - frame_pointer_rtx)); + hard_frame_pointer_rtx)); } else { - emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); + emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx); } fp_plus_insns = get_insns (); @@ -1228,32 +1227,8 @@ avr_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) memory address for an operand of mode MODE */ rtx -avr_legitimize_address (rtx x, rtx oldx, enum machine_mode mode) +avr_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED) { - x = oldx; - if (TARGET_ALL_DEBUG) - { - fprintf (stderr, "legitimize_address mode: %s", GET_MODE_NAME(mode)); - debug_rtx (oldx); - } - - if (GET_CODE (oldx) == PLUS - && REG_P (XEXP (oldx,0))) - { - if (REG_P (XEXP (oldx,1))) - x = force_reg (GET_MODE (oldx), oldx); - else if (GET_CODE (XEXP (oldx, 1)) == CONST_INT) - { - int offs = INTVAL (XEXP (oldx,1)); - if (frame_pointer_rtx != XEXP (oldx,0)) - if (offs > MAX_LD_OFFSET (mode)) - { - if (TARGET_ALL_DEBUG) - fprintf (stderr, "force_reg (big offset)\n"); - x = force_reg (GET_MODE (oldx), oldx); - } - } - } return x; } @@ -6096,8 +6071,7 @@ extra_constraint_Q (rtx x) return 1; /* allocate pseudos */ else if (regno == REG_Z || regno == REG_Y) return 1; /* strictly check */ - else if (xx == frame_pointer_rtx - || xx == arg_pointer_rtx) + else if (xx == frame_pointer_rtx || xx == arg_pointer_rtx) return 1; /* XXX frame & arg pointer checks */ } return 0; @@ -6280,6 +6254,18 @@ jump_over_one_insn_p (rtx insn, rtx dest) return dest_addr - jump_addr == get_attr_length (insn) + 1; } +/* Returns the number of registers required to hold a value of MODE. */ + +int +avr_hard_regno_nregs (int regno, enum machine_mode mode) +{ + /* The fake registers are designed to hold exactly a pointer. */ + if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM) + return 1; + + return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; +} + /* Returns 1 if a value of mode MODE can be stored starting with hard register number REGNO. On the enhanced core, anything larger than 1 byte must start in even numbered register for "movw" to work @@ -6288,6 +6274,10 @@ jump_over_one_insn_p (rtx insn, rtx dest) int avr_hard_regno_mode_ok (int regno, enum machine_mode mode) { + /* The fake registers are designed to hold exactly a pointer. */ + if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM) + return mode == Pmode; + /* Any GENERAL_REGS register can hold 8-bit values. */ /* FIXME: 8-bit values must not be disallowed for R28 or R29. Disallowing QI et al. in these registers might lead to code like @@ -6299,8 +6289,7 @@ avr_hard_regno_mode_ok (int regno, enum machine_mode mode) if (GET_MODE_SIZE (mode) == 1) return 1; - /* All modes larger than 8 bits should start in an even register. */ - + /* All modes larger than 8 bits should start in an even register. */ return regno % 2 == 0; } @@ -6332,27 +6321,35 @@ avr_mode_code_base_reg_class (enum machine_mode mode ATTRIBUTE_UNUSED, /* Worker function for `REGNO_MODE_CODE_OK_FOR_BASE_P'. */ bool -avr_regno_mode_code_ok_for_base_p (int regno, enum machine_mode mode ATTRIBUTE_UNUSED, - RTX_CODE outer_code, RTX_CODE index_code ATTRIBUTE_UNUSED) +avr_regno_mode_code_ok_for_base_p (int regno, + enum machine_mode mode ATTRIBUTE_UNUSED, + RTX_CODE outer_code, + RTX_CODE index_code ATTRIBUTE_UNUSED) { bool ok; + ok = (regno == REG_Z + || regno == REG_Y + || regno == ARG_POINTER_REGNUM + || regno == FRAME_POINTER_REGNUM); + switch (outer_code) { case PLUS: - ok = regno == REG_Z || regno == REG_Y; + /* Computed above */ break; case MEM: /* plain reg */ case POST_INC: case PRE_DEC: - ok = regno == REG_Z || regno == REG_Y || regno == REG_X; + /* As above, but also X. */ + if (regno == REG_X) + ok = true; break; default: ok = false; break; - } return ok; diff --git a/gcc/config/avr/avr.h b/gcc/config/avr/avr.h index 9c64f96..426ddec 100644 --- a/gcc/config/avr/avr.h +++ b/gcc/config/avr/avr.h @@ -191,7 +191,8 @@ extern GTY(()) section *progmem_section; 0,0,/* r28 r29 */\ 0,0,/* r30 r31 */\ 1,1,/* STACK */\ - 1,1 /* arg pointer */ } + 1, /* arg pointer */\ + 1 /* frame pointer */ } #define CALL_USED_REGISTERS { \ 1,1,/* r0 r1 */ \ @@ -211,7 +212,8 @@ extern GTY(()) section *progmem_section; 0,0,/* r28 r29 */ \ 1,1,/* r30 r31 */ \ 1,1,/* STACK */ \ - 1,1 /* arg pointer */ } + 1, /* arg pointer */ \ + 1 /* frame pointer */ } #define REG_ALLOC_ORDER { \ 24,25, \ @@ -229,7 +231,7 @@ extern GTY(()) section *progmem_section; #define ADJUST_REG_ALLOC_ORDER order_regs_for_local_alloc () -#define HARD_REGNO_NREGS(REGNO, MODE) ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) +#define HARD_REGNO_NREGS(REGNO, MODE) avr_hard_regno_nregs(REGNO, MODE) #define HARD_REGNO_MODE_OK(REGNO, MODE) avr_hard_regno_mode_ok(REGNO, MODE) @@ -279,17 +281,17 @@ enum reg_class { {3 << REG_Z,0x00000000}, /* POINTER_Z_REGS, r30 - r31 */ \ {0x00000000,0x00000003}, /* STACK_REG, STACK */ \ {(3 << REG_Y) | (3 << REG_Z), \ - 0x00000000}, /* BASE_POINTER_REGS, r28 - r31 */ \ + 0x0000000c}, /* BASE_POINTER_REGS, r28 - r31,ap,fp */\ {(3 << REG_X) | (3 << REG_Y) | (3 << REG_Z), \ - 0x00000000}, /* POINTER_REGS, r26 - r31 */ \ + 0x0000000c}, /* POINTER_REGS, r26 - r31,ap,fp */ \ {(3 << REG_X) | (3 << REG_Y) | (3 << REG_Z) | (3 << REG_W), \ 0x00000000}, /* ADDW_REGS, r24 - r31 */ \ {0x00ff0000,0x00000000}, /* SIMPLE_LD_REGS r16 - r23 */ \ {(3 << REG_X)|(3 << REG_Y)|(3 << REG_Z)|(3 << REG_W)|(0xff << 16), \ - 0x00000000}, /* LD_REGS, r16 - r31 */ \ + 0x0000000c}, /* LD_REGS, r16 - r31 */ \ {0x0000ffff,0x00000000}, /* NO_LD_REGS r0 - r15 */ \ - {0xffffffff,0x00000000}, /* GENERAL_REGS, r0 - r31 */ \ - {0xffffffff,0x00000003} /* ALL_REGS */ \ + {0xffffffff,0x0000000c}, /* GENERAL_REGS, r0 - r31,ap,fp */ \ + {0xffffffff,0x0000000f} /* ALL_REGS */ \ } #define REGNO_REG_CLASS(R) avr_regno_reg_class(R) @@ -322,16 +324,18 @@ enum reg_class { #define STACK_POINTER_REGNUM 32 -#define FRAME_POINTER_REGNUM REG_Y +#define HARD_FRAME_POINTER_REGNUM REG_Y #define ARG_POINTER_REGNUM 34 +#define FRAME_POINTER_REGNUM 35 #define STATIC_CHAIN_REGNUM 2 #define ELIMINABLE_REGS { \ - {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ - {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM} \ - ,{FRAME_POINTER_REGNUM+1,STACK_POINTER_REGNUM+1}} + { ARG_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ + { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM }, \ + { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ + { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM }} #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ OFFSET = avr_initial_elimination_offset (FROM, TO) @@ -582,7 +586,7 @@ sprintf (STRING, "*.%s%lu", PREFIX, (unsigned long)(NUM)) "r8","r9","r10","r11","r12","r13","r14","r15", \ "r16","r17","r18","r19","r20","r21","r22","r23", \ "r24","r25","r26","r27","r28","r29","r30","r31", \ - "__SP_L__","__SP_H__","argL","argH"} + "__SP_L__","__SP_H__","ap","fp"} #define FINAL_PRESCAN_INSN(insn, operand, nop) final_prescan_insn (insn, operand,nop)