From patchwork Sat Nov 20 19:13:43 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Koning X-Patchwork-Id: 72359 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 A35171007D2 for ; Sun, 21 Nov 2010 06:13:55 +1100 (EST) Received: (qmail 2323 invoked by alias); 20 Nov 2010 19:13:54 -0000 Received: (qmail 2313 invoked by uid 22791); 20 Nov 2010 19:13:52 -0000 X-SWARE-Spam-Status: No, hits=-0.5 required=5.0 tests=AWL, BAYES_00, SARE_RAND_2, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from ausxippc101.us.dell.com (HELO ausxippc101.us.dell.com) (143.166.85.207) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sat, 20 Nov 2010 19:13:47 +0000 X-Loopcount0: from 10.152.240.141 Subject: Re: [PATCH] pdp11: Fix bad code for no frame pointer case Mime-Version: 1.0 (Apple Message framework v1081) From: Paul Koning In-Reply-To: <4CE6B4F0.1070408@redhat.com> Date: Sat, 20 Nov 2010 14:13:43 -0500 Cc: gcc-patches Message-Id: <92B7C6C9-87B1-4E4E-A4B8-6419EA3A41F2@dell.com> References: <4CE6B4F0.1070408@redhat.com> To: Richard Henderson 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 Nov 19, 2010, at 12:33 PM, Richard Henderson wrote: > On 11/18/2010 06:04 PM, Paul Koning wrote: >> -#define FIRST_PARM_OFFSET(FNDECL) 4 >> +#define FIRST_PARM_OFFSET(FNDECL) ((frame_pointer_needed) ? 4 : 2) > > This is a sign of broken register elimination. ... Sure enough. Fixed by borrowing from the i386 example. Thanks Richard. The result is a dramatic improvement in the number of testcases that pass. Checked by test build and make check. Committed. paul ChangeLog: 2010-11-20 Paul Koning * config/pdp11/pdp11-protos.h (pdp11_initial_elimination_offset, pdp11_regno_reg_class): New functions. * config/pdp11/pdp11.md (define_constants): Add register numbers. * config/pdp11/pdp11.c (pdp11_regno_reg_class, pdp11_sp_frame_offset, pdp11_initial_elimination_offset): New functions. * config/pdp11/pdp11.h (FIXED_REGISTERS, CALL_USED_REGISTERS): Add frame pointer and argument pointer pseudo-registers. (ARG_POINTER_REGNUM): Define. (REG_CLASS_CONTENTS, REGNO_REG_CLASS): Add frame pointer and argument pointer. (FIRST_PARM_OFFSET): Update for argument pointer. (INITIAL_FRAME_POINTER_OFFSET): Delete. (ELIMINABLE_REGS, INITIAL_ELIMINATION_OFFSET): New macros. (REGNO_OK_FOR_BASE_P, REGNO_OK_FOR_INDEX_P, REGISTER_NAMES): Add frame pointer and argument pointer. Index: config/pdp11/pdp11-protos.h =================================================================== --- config/pdp11/pdp11-protos.h (revision 166977) +++ config/pdp11/pdp11-protos.h (working copy) @@ -35,6 +35,8 @@ enum machine_mode, enum reg_class); extern bool pdp11_secondary_memory_needed (reg_class_t, reg_class_t, enum machine_mode); +extern int pdp11_initial_elimination_offset (int, int); +extern enum reg_class pdp11_regno_reg_class (int); #endif /* RTX_CODE */ Index: config/pdp11/pdp11.md =================================================================== --- config/pdp11/pdp11.md (revision 166977) +++ config/pdp11/pdp11.md (working copy) @@ -25,15 +25,20 @@ (define_constants [ ;; Register numbers + (R0_REGNUM 0) (RETVAL_REGNUM 0) - (FRAME_POINTER_REGNUM 5) + (HARD_FRAME_POINTER_REGNUM 5) (STACK_POINTER_REGNUM 6) (PC_REGNUM 7) (AC0_REGNUM 8) (AC3_REGNUM 11) (AC4_REGNUM 12) (AC5_REGNUM 13) - (FIRST_PSEUDO_REGISTER 14) + ;; The next two are not physical registers but are used for addressing + ;; arguments. + (FRAME_POINTER_REGNUM 14) + (ARG_POINTER_REGNUM 15) + (FIRST_PSEUDO_REGISTER 16) ;; Branch offset limits, as byte offsets from instruction address (MIN_BRANCH -254) (MAX_BRANCH 256) Index: config/pdp11/pdp11.c =================================================================== --- config/pdp11/pdp11.c (revision 166977) +++ config/pdp11/pdp11.c (working copy) @@ -300,7 +300,7 @@ asm_fprintf (stream, "\tsub $%#wo, sp\n", fsize); /* save CPU registers */ - for (regno = 0; regno <= PC_REGNUM; regno++) + for (regno = R0_REGNUM; regno <= PC_REGNUM; regno++) if (df_regs_ever_live_p (regno) && ! call_used_regs[regno]) if (! ((regno == FRAME_POINTER_REGNUM) && frame_pointer_needed)) @@ -379,7 +379,7 @@ k = 2*j; /* change fp -> r5 due to the compile error on libgcc2.c */ - for (i = PC_REGNUM ; i >= 0 ; i--) + for (i = PC_REGNUM ; i >= R0_REGNUM ; i--) if (df_regs_ever_live_p (i) && ! call_used_regs[i]) fprintf(stream, "\tmov %#" HOST_WIDE_INT_PRINT "o(r5), %s\n", (-fsize-2*j--)&0xffff, reg_names[i]); @@ -1706,7 +1706,72 @@ return (fromfloat != tofloat); } +/* Return the class number of the smallest class containing + reg number REGNO. */ +enum reg_class +pdp11_regno_reg_class (int regno) +{ + if (regno == FRAME_POINTER_REGNUM || regno == ARG_POINTER_REGNUM) + return GENERAL_REGS; + else if (regno > AC3_REGNUM) + return NO_LOAD_FPU_REGS; + else if (regno >= AC0_REGNUM) + return LOAD_FPU_REGS; + else if (regno & 1) + return MUL_REGS; + else + return GENERAL_REGS; +} + +static int +pdp11_sp_frame_offset (void) +{ + int offset = 0, regno; + offset = get_frame_size(); + for (regno = 0; regno <= PC_REGNUM; regno++) + if (df_regs_ever_live_p (regno) && ! call_used_regs[regno]) + offset += 2; + for (regno = AC0_REGNUM; regno <= AC5_REGNUM; regno++) + if (df_regs_ever_live_p (regno) && ! call_used_regs[regno]) + offset += 8; + + return offset; +} + +/* Return the offset between two registers, one to be eliminated, and the other + its replacement, at the start of a routine. */ + +int +pdp11_initial_elimination_offset (int from, int to) +{ + int spoff; + + if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) + return 4; + else if (from == FRAME_POINTER_REGNUM + && to == HARD_FRAME_POINTER_REGNUM) + return 0; + else + { + gcc_assert (to == STACK_POINTER_REGNUM); + + /* Get the size of the register save area. */ + spoff = pdp11_sp_frame_offset (); + if (from == FRAME_POINTER_REGNUM) + return spoff; + + gcc_assert (from == ARG_POINTER_REGNUM); + + /* If there is a frame pointer, that is saved too. */ + if (frame_pointer_needed) + spoff += 2; + + /* Account for the saved PC in the function call. */ + return spoff + 2; + } +} + /* A copy of output_addr_const modified for pdp11 expression syntax. output_addr_const also gets called for %cDIGIT and %nDIGIT, which we don't use, and for debugging output, which we don't support with this port either. Index: config/pdp11/pdp11.h =================================================================== --- config/pdp11/pdp11.h (revision 166977) +++ config/pdp11/pdp11.h (working copy) @@ -149,11 +149,9 @@ reg 5 = fp; not necessarily! */ -/* don't let them touch fp regs for the time being !*/ - #define FIXED_REGISTERS \ {0, 0, 0, 0, 0, 0, 1, 1, \ - 0, 0, 0, 0, 0, 0 } + 0, 0, 0, 0, 0, 0, 1, 1 } @@ -167,7 +165,7 @@ /* don't know about fp */ #define CALL_USED_REGISTERS \ {1, 1, 0, 0, 0, 0, 1, 1, \ - 0, 0, 0, 0, 0, 0 } + 0, 0, 0, 0, 0, 0, 1, 1 } /* Make sure everything's fine if we *don't* have an FPU. @@ -183,7 +181,7 @@ if (!TARGET_FPU) \ { \ COPY_HARD_REG_SET (x, reg_class_contents[(int)FPU_REGS]); \ - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++ ) \ + for (i = R0_REGNUM; i < FIRST_PSEUDO_REGISTER; i++ ) \ if (TEST_HARD_REG_BIT (x, i)) \ fixed_regs[i] = call_used_regs[i] = 1; \ } \ @@ -239,9 +237,6 @@ /* Specify the registers used for certain standard purposes. The values of these macros are register numbers. */ -/* Base register for access to arguments of the function. */ -#define ARG_POINTER_REGNUM FRAME_POINTER_REGNUM - /* Register in which static-chain is passed to a function. */ /* ??? - i don't want to give up a reg for this! */ #define STATIC_CHAIN_REGNUM 4 @@ -298,20 +293,15 @@ This is an initializer for a vector of HARD_REG_SET of length N_REG_CLASSES. */ -#define REG_CLASS_CONTENTS {{0}, {0x00aa}, {0x00ff}, {0x0f00}, {0x3000}, {0x3f00}, {0x3fff}} +#define REG_CLASS_CONTENTS {{0}, {0x00aa}, {0xc0ff}, {0x0f00}, {0x3000}, {0x3f00}, {0xffff}} /* The same information, inverted: Return the class number of the smallest class containing reg number REGNO. This could be a conditional expression or could index an array. */ -#define REGNO_REG_CLASS(REGNO) \ -((REGNO) >= AC0_REGNUM ? \ - ((REGNO) <= AC3_REGNUM ? LOAD_FPU_REGS : \ - NO_LOAD_FPU_REGS) : \ - (((REGNO) & 1) ? MUL_REGS : GENERAL_REGS)) +#define REGNO_REG_CLASS(REGNO) pdp11_regno_reg_class (REGNO) - /* The class value for index registers, and the one for base regs. */ #define INDEX_REG_CLASS GENERAL_REGS #define BASE_REG_CLASS GENERAL_REGS @@ -369,14 +359,9 @@ stack */ extern int current_first_parm_offset; -/* Offset of first parameter from the argument pointer register value. - For the pdp11, this is nonzero to account for the return address. - 1 - return address - 2 - frame pointer, if needed +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 0 -*/ -#define FIRST_PARM_OFFSET(FNDECL) ((frame_pointer_needed) ? 4 : 2) - /* Define how to find the value returned by a function. VALTYPE is the data type of the value (as a tree). If the precise function being called is known, FUNC is its FUNCTION_DECL; @@ -425,20 +410,28 @@ #define EXIT_IGNORE_STACK 1 -#define INITIAL_FRAME_POINTER_OFFSET(DEPTH_VAR) \ -{ \ - int offset, regno; \ - offset = get_frame_size(); \ - for (regno = 0; regno <= PC_REGNUM; regno++) \ - if (df_regs_ever_live_p (regno) && ! call_used_regs[regno]) \ - offset += 2; \ - for (regno = AC0_REGNUM; regno <= AC5_REGNUM; regno++) \ - if (df_regs_ever_live_p (regno) && ! call_used_regs[regno]) \ - offset += 8; \ - /* offset -= 2; no fp on stack frame */ \ - (DEPTH_VAR) = offset; \ -} - +/* Definitions for register eliminations. + + This is an array of structures. Each structure initializes one pair + of eliminable registers. The "from" register number is given first, + followed by "to". Eliminations of the same "from" register are listed + in order of preference. + + There are two registers that can always be eliminated on the pdp11. + The frame pointer and the arg pointer can be replaced by either the + hard frame pointer or to the stack pointer, depending upon the + circumstances. The hard frame pointer is not used before reload and + so it is not eligible for elimination. */ + +#define ELIMINABLE_REGS \ +{{ 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) = pdp11_initial_elimination_offset ((FROM), (TO))) + /* Addressing modes, and classification of registers for them. */ @@ -454,11 +447,12 @@ Since they use reg_renumber, they are safe only once reg_renumber has been allocated, which happens in local-alloc.c. */ -#define REGNO_OK_FOR_INDEX_P(REGNO) \ - ((REGNO) <= PC_REGNUM || (unsigned) reg_renumber[REGNO] <= PC_REGNUM) #define REGNO_OK_FOR_BASE_P(REGNO) \ - ((REGNO) <= PC_REGNUM || (unsigned) reg_renumber[REGNO] <= PC_REGNUM) + ((REGNO) <= PC_REGNUM || (unsigned) reg_renumber[REGNO] <= PC_REGNUM || \ + (REGNO) == ARG_POINTER_REGNUM || (REGNO) == FRAME_POINTER_REGNUM) +#define REGNO_OK_FOR_INDEX_P(REGNO) REGNO_OK_FOR_BASE_P (REGNO) + /* Now macros that check whether X is a register and also, strictly, whether it is in a specified class. */ @@ -743,7 +737,7 @@ #define REGISTER_NAMES \ {"r0", "r1", "r2", "r3", "r4", "r5", "sp", "pc", \ - "ac0", "ac1", "ac2", "ac3", "ac4", "ac5" } + "ac0", "ac1", "ac2", "ac3", "ac4", "ac5", "fp", "ap" } /* Globalizing directive for a label. */ #define GLOBAL_ASM_OP "\t.globl "