From 5a1acad9501c4a544f501004495507534e67a9d1 Mon Sep 17 00:00:00 2001 From: rth Date: Tue, 30 Nov 1999 22:18:21 +0000 Subject: [PATCH] Jakub Jelinek * config/sparc/sparc.h (FIXED_REGISTERS, CONDITIONAL_REGISTER_USAGE): Allow the user to override call-used/fixed state of %g2-5 registers from the command line (with the exception of %g4 for embedded model). (REG_LEAF_ALLOC_ORDER): Move %g1 and %g4-7 registers to front, so that there is a higher chance of having a leaf function. (MACHINE_STATE_SAVE, MACHINE_STATE_RESTORE): Provide separate macros for ARCH64 which has %ccr register. * config/sparc/sparc.md (return_losum_si, return_losum_di): New patterns. * config/sparc/sparc.c (eligible_for_epilogue_delay): For the return insn accept into delay slot any insn which does not use %[ol] registers. Accept some LO_SUM and shift left by 1 for the normal restore case. (output_function_epilogue): Likewise. (epilogue_renumber): Added argument which inhibits any renumbering and just tests if the rtx does not use any %[ol] registers. (output_return): Reflect above change. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@30727 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 21 ++++++ gcc/config/sparc/sparc.c | 169 ++++++++++++++++++++++++++++++---------------- gcc/config/sparc/sparc.h | 78 ++++++++++++++++----- gcc/config/sparc/sparc.md | 27 ++++++++ 4 files changed, 220 insertions(+), 75 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 861774f..6210e8a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,26 @@ 1999-11-30 Jakub Jelinek + * config/sparc/sparc.h (FIXED_REGISTERS, CONDITIONAL_REGISTER_USAGE): + Allow the user to override call-used/fixed state of %g2-5 + registers from the command line (with the exception of %g4 for + embedded model). + (REG_LEAF_ALLOC_ORDER): Move %g1 and %g4-7 registers to front, so that + there is a higher chance of having a leaf function. + (MACHINE_STATE_SAVE, MACHINE_STATE_RESTORE): Provide separate macros + for ARCH64 which has %ccr register. + * config/sparc/sparc.md (return_losum_si, return_losum_di): New + patterns. + * config/sparc/sparc.c (eligible_for_epilogue_delay): For the return + insn accept into delay slot any insn which does not use %[ol] + registers. Accept some LO_SUM and shift left by 1 for the normal + restore case. + (output_function_epilogue): Likewise. + (epilogue_renumber): Added argument which inhibits any renumbering + and just tests if the rtx does not use any %[ol] registers. + (output_return): Reflect above change. + +1999-11-30 Jakub Jelinek + * config/sparc/sparc.c (sparc_va_arg): Fix sparc64 va_arg aggregate passing for sizes <= 16 bytes. diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 54c0230..22c0fbf 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -63,6 +63,10 @@ Boston, MA 02111-1307, USA. */ static int apparent_fsize; static int actual_fsize; +/* Number of live general or floating point registers needed to be saved + (as 4-byte quantities). This is only done if TARGET_EPILOGUE. */ +static int num_gfregs; + /* Save the operands last given to a compare for use when we generate a scc or bcc insn. */ @@ -124,7 +128,7 @@ static void sparc_output_deferred_case_vectors PROTO((void)); static void sparc_add_gc_roots PROTO ((void)); static void mark_ultrasparc_pipeline_state PROTO ((void *)); static int check_return_regs PROTO ((rtx)); -static void epilogue_renumber PROTO ((rtx *)); +static int epilogue_renumber PROTO ((rtx *, int)); static int ultra_cmove_results_ready_p PROTO ((rtx)); static int ultra_fpmode_conflict_exists PROTO ((enum machine_mode)); static rtx *ultra_find_type PROTO ((int, rtx *, int)); @@ -2208,6 +2212,11 @@ eligible_for_epilogue_delay (trial, slot) optimize things as necessary. */ if (TARGET_LIVE_G0) return 0; + + /* If there are any call-saved registers, we should scan TRIAL if it + does not reference them. For now just make it easy. */ + if (num_gfregs) + return 0; /* In the case of a true leaf function, anything can go into the delay slot. A delay slot only exists however if the frame size is zero, otherwise @@ -2228,7 +2237,7 @@ eligible_for_epilogue_delay (trial, slot) pat = PATTERN (trial); /* Otherwise, only operations which can be done in tandem with - a `restore' insn can go into the delay slot. */ + a `restore' or `return' insn can go into the delay slot. */ if (GET_CODE (SET_DEST (pat)) != REG || REGNO (SET_DEST (pat)) >= 32 || REGNO (SET_DEST (pat)) < 24) @@ -2247,7 +2256,7 @@ eligible_for_epilogue_delay (trial, slot) else return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode); } - + /* This matches "*return_di". */ else if (arith_double_operand (src, GET_MODE (src))) return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode); @@ -2257,6 +2266,12 @@ eligible_for_epilogue_delay (trial, slot) && register_operand (src, SFmode)) return 1; + /* If we have return instruction, anything that does not use + local or output registers and can go into a delay slot wins. */ + else if (TARGET_V9 && ! epilogue_renumber (&pat, 1) + && (get_attr_in_uncond_branch_delay (trial) == IN_BRANCH_DELAY_TRUE)) + return 1; + /* This matches "*return_addsi". */ else if (GET_CODE (src) == PLUS && arith_operand (XEXP (src, 0), SImode) @@ -2273,6 +2288,25 @@ eligible_for_epilogue_delay (trial, slot) || register_operand (XEXP (src, 1), DImode))) return 1; + /* This can match "*return_losum_[sd]i". + Catch only some cases, so that return_losum* don't have + to be too big. */ + else if (GET_CODE (src) == LO_SUM + && ! TARGET_CM_MEDMID + && ((register_operand (XEXP (src, 0), SImode) + && immediate_operand (XEXP (src, 1), SImode)) + || (TARGET_ARCH64 + && register_operand (XEXP (src, 0), DImode) + && immediate_operand (XEXP (src, 1), DImode)))) + return 1; + + /* sll{,x} reg,1,reg2 is add reg,reg,reg2 as well. */ + else if (GET_CODE (src) == ASHIFT + && (register_operand (XEXP (src, 0), SImode) + || register_operand (XEXP (src, 0), DImode)) + && XEXP (src, 1) == const1_rtx) + return 1; + return 0; } @@ -2979,12 +3013,6 @@ restore_regs (file, low, high, base, offset, n_regs) return n_regs; } -/* Static variables we want to share between prologue and epilogue. */ - -/* Number of live general or floating point registers needed to be saved - (as 4-byte quantities). This is only done if TARGET_EPILOGUE. */ -static int num_gfregs; - /* Compute the frame size required by the function. This function is called during the reload pass and also by output_function_prologue(). */ @@ -3283,7 +3311,7 @@ output_function_epilogue (file, size, leaf_function) #endif else if (current_function_epilogue_delay_list == 0) - { + { /* If code does not drop into the epilogue, we need do nothing except output pending case vectors. */ rtx insn = get_last_insn (); @@ -3339,13 +3367,38 @@ output_function_epilogue (file, size, leaf_function) /* If we wound up with things in our delay slot, flush them here. */ if (current_function_epilogue_delay_list) { - rtx insn = emit_jump_insn_after (gen_rtx_RETURN (VOIDmode), - get_last_insn ()); - PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode, - gen_rtvec (2, - PATTERN (XEXP (current_function_epilogue_delay_list, 0)), - PATTERN (insn))); - final_scan_insn (insn, file, 1, 0, 1); + rtx delay = PATTERN (XEXP (current_function_epilogue_delay_list, 0)); + + if (TARGET_V9 && ! epilogue_renumber (&delay, 1)) + { + epilogue_renumber (&delay, 0); + fputs (SKIP_CALLERS_UNIMP_P + ? "\treturn\t%i7+12\n" + : "\treturn\t%i7+8\n", file); + final_scan_insn (XEXP (current_function_epilogue_delay_list, 0), file, 1, 0, 0); + } + else + { + rtx insn = emit_jump_insn_after (gen_rtx_RETURN (VOIDmode), + get_last_insn ()); + rtx src; + + if (GET_CODE (delay) != SET) + abort(); + + src = SET_SRC (delay); + if (GET_CODE (src) == ASHIFT) + { + if (XEXP (src, 1) != const1_rtx) + abort(); + SET_SRC (delay) = gen_rtx_PLUS (GET_MODE (src), XEXP (src, 0), + XEXP (src, 0)); + } + + PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode, + gen_rtvec (2, delay, PATTERN (insn))); + final_scan_insn (insn, file, 1, 0, 1); + } } else if (TARGET_V9 && ! SKIP_CALLERS_UNIMP_P) fputs ("\treturn\t%i7+8\n\tnop\n", file); @@ -4726,56 +4779,56 @@ output_v9branch (op, reg, label, reversed, annul, noop, insn) return string; } -/* Renumber registers in delay slot. Replace registers instead of - renumbering because they may be shared. - - This does not handle instructions other than move. */ +/* Return 1, if any of the registers of the instruction are %l[0-7] or %o[0-7]. + Such instructions cannot be used in the delay slot of return insn on v9. + If TEST is 0, also rename all %i[0-7] registers to their %o[0-7] counterparts. + */ -static void -epilogue_renumber (where) - rtx *where; +static int +epilogue_renumber (where, test) + register rtx *where; + int test; { - rtx x = *where; - enum rtx_code code = GET_CODE (x); + register const char *fmt; + register int i; + register enum rtx_code code; + + if (*where == 0) + return 0; + + code = GET_CODE (*where); switch (code) { - case MEM: - *where = x = copy_rtx (x); - epilogue_renumber (&XEXP (x, 0)); - return; - case REG: - { - int regno = REGNO (x); - if (regno > 8 && regno < 24) - abort (); - if (regno >= 24 && regno < 32) - *where = gen_rtx_REG (GET_MODE (x), regno - 16); - return; - } + if (REGNO (*where) >= 8 && REGNO (*where) < 24) /* oX or lX */ + return 1; + if (! test && REGNO (*where) >= 24 && REGNO (*where) < 32) + *where = gen_rtx (REG, GET_MODE (*where), OUTGOING_REGNO (REGNO(*where))); + case SCRATCH: + case CC0: + case PC: case CONST_INT: case CONST_DOUBLE: - case CONST: - case SYMBOL_REF: - case LABEL_REF: - return; + return 0; + } - case IOR: - case AND: - case XOR: - case PLUS: - case MINUS: - epilogue_renumber (&XEXP (x, 1)); - case NEG: - case NOT: - epilogue_renumber (&XEXP (x, 0)); - return; + fmt = GET_RTX_FORMAT (code); - default: - debug_rtx (*where); - abort (); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'E') + { + register int j; + for (j = XVECLEN (*where, i) - 1; j >= 0; j--) + if (epilogue_renumber (&(XVECEXP (*where, i, j)), test)) + return 1; + } + else if (fmt[i] == 'e' + && epilogue_renumber (&(XEXP (*where, i)), test)) + return 1; } + return 0; } /* Output assembler code to return from a function. */ @@ -4840,8 +4893,8 @@ output_return (operands) { if (delay) { - epilogue_renumber (&SET_DEST (PATTERN (delay))); - epilogue_renumber (&SET_SRC (PATTERN (delay))); + epilogue_renumber (&SET_DEST (PATTERN (delay)), 0); + epilogue_renumber (&SET_SRC (PATTERN (delay)), 0); } if (SKIP_CALLERS_UNIMP_P) return "return\t%%i7+12%#"; diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index 7d02de3..f402b83 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -962,7 +962,7 @@ if (TARGET_ARCH64 \ */ #define FIXED_REGISTERS \ - {1, 0, 0, 0, 0, 0, 1, 1, \ + {1, 0, 2, 2, 2, 2, 1, 1, \ 0, 0, 0, 0, 0, 0, 1, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 1, 1, \ @@ -1015,10 +1015,12 @@ do \ fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ } \ - if (TARGET_ARCH32) \ - { \ - fixed_regs[5] = 1; \ - } \ + /* If the user has passed -f{fixed,call-{used,saved}}-g5 */ \ + /* then honour it. */ \ + if (TARGET_ARCH32 && fixed_regs[5]) \ + fixed_regs[5] = 1; \ + else if (TARGET_ARCH64 && fixed_regs[5] == 2) \ + fixed_regs[5] = 0; \ if (TARGET_LIVE_G0) \ fixed_regs[0] = 0; \ if (! TARGET_V9) \ @@ -1040,10 +1042,18 @@ do \ for (regno = 32; regno < SPARC_LAST_V9_FCC_REG; regno++) \ fixed_regs[regno] = 1; \ } \ - /* Don't unfix g2-g4 if they were fixed with -ffixed-. */ \ - fixed_regs[2] |= ! TARGET_APP_REGS; \ - fixed_regs[3] |= ! TARGET_APP_REGS; \ - fixed_regs[4] |= ! TARGET_APP_REGS || TARGET_CM_EMBMEDANY; \ + /* If the user has passed -f{fixed,call-{used,saved}}-g2 */ \ + /* then honour it. Likewise with g3 and g4. */ \ + if (fixed_regs[2] == 2) \ + fixed_regs[2] = ! TARGET_APP_REGS; \ + if (fixed_regs[3] == 2) \ + fixed_regs[3] = ! TARGET_APP_REGS; \ + if (TARGET_ARCH32 && fixed_regs[4] == 2) \ + fixed_regs[4] = ! TARGET_APP_REGS; \ + else if (TARGET_CM_EMBMEDANY) \ + fixed_regs[4] = 1; \ + else if (fixed_regs[4] == 2) \ + fixed_regs[4] = 0; \ if (TARGET_FLAT) \ { \ /* Let the compiler believe the frame pointer is still \ @@ -1335,11 +1345,12 @@ extern enum reg_class sparc_regno_reg_class[]; 1, 4, 5, 6, 7, 0, 14, 30} /* This is the order in which to allocate registers for - leaf functions. If all registers can fit in the "i" registers, + leaf functions. If all registers can fit in the "gi" registers, then we have the possibility of having a leaf function. */ #define REG_LEAF_ALLOC_ORDER \ { 2, 3, 24, 25, 26, 27, 28, 29, \ + 4, 5, 6, 7, 1, \ 15, 8, 9, 10, 11, 12, 13, \ 16, 17, 18, 19, 20, 21, 22, 23, \ 34, 35, 36, 37, 38, 39, \ @@ -1352,8 +1363,8 @@ extern enum reg_class sparc_regno_reg_class[]; 88, 89, 90, 91, 92, 93, 94, 95, \ 32, 33, \ 96, 97, 98, 99, 100, \ - 1, 4, 5, 6, 7, 0, 14, 30, 31} - + 0, 14, 30, 31} + #define ORDER_REGS_FOR_LOCAL_ALLOC order_regs_for_local_alloc () /* ??? %g7 is not a leaf register to effectively #undef LEAF_REGISTERS when @@ -1889,6 +1900,8 @@ do { \ #define FUNCTION_BLOCK_PROFILER_EXIT(FILE) \ sparc_function_block_profiler_exit(FILE) +#ifdef IN_LIBGCC2 + /* The function `__bb_trace_func' is called in every basic block and is not allowed to change the machine state. Saving (restoring) the state can either be done in the BLOCK_PROFILER macro, @@ -1908,12 +1921,18 @@ do { \ On sparc it is sufficient to save the psw register to memory. Unfortunately the psw register can be read in supervisor mode only, so we read only the condition codes by using branch instructions - and hope that this is enough. */ + and hope that this is enough. + + On V9, life is much sweater: there is a user accessible %ccr + register, but we use it for 64bit libraries only. */ + +#if TARGET_ARCH32 #define MACHINE_STATE_SAVE(ID) \ int ms_flags, ms_saveret; \ asm volatile( \ - "mov %%g0,%0\n\ + "mov %%g2,%1\n\ + mov %%g0,%0\n\ be,a LFLGNZ"ID"\n\ or %0,4,%0\n\ LFLGNZ"ID":\n\ @@ -1925,10 +1944,20 @@ LFLGNC"ID":\n\ LFLGNV"ID":\n\ bneg,a LFLGNN"ID"\n\ or %0,8,%0\n\ -LFLGNN"ID":\n\ - mov %%g2,%1" \ +LFLGNN"ID":" \ + : "=r"(ms_flags), "=r"(ms_saveret)); + +#else + +#define MACHINE_STATE_SAVE(ID) \ + unsigned long ms_flags, ms_saveret; \ + asm volatile( \ + "mov %%g2,%1\n\ \ + rd %%ccr,%0" \ : "=r"(ms_flags), "=r"(ms_saveret)); +#endif + /* On sparc MACHINE_STATE_RESTORE restores the psw register from memory. The psw register can be written in supervisor mode only, which is true even for simple condition codes. @@ -1937,6 +1966,8 @@ LFLGNN"ID":\n\ be generated in this way. If this happens an unimplemented instruction will be executed to abort the program. */ +#if TARGET_ARCH32 + #define MACHINE_STATE_RESTORE(ID) \ { extern char flgtab[] __asm__("LFLGTAB"ID); \ int scratch; \ @@ -1995,7 +2026,20 @@ LFLGRET"ID":\n\ : "=r"(scratch) \ : "r"(ms_flags*8), "r"(flgtab), "r"(-1), \ "r"(0x80000000), "r"(ms_saveret) \ - : "cc", "%g2"); } + : "cc", "g2"); } + +#else + +#define MACHINE_STATE_RESTORE(ID) \ + asm volatile ( \ + "wr %0,0,%%ccr\n\ + mov %1,%%g2" \ + : : "r"(ms_flags), "r"(ms_saveret) \ + : "cc", "g2"); + +#endif + +#endif /* IN_LIBGCC2 */ /* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, the stack pointer does not matter. The value is tested only in diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index 90d8641..95c6868 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -8191,6 +8191,24 @@ }" [(set_attr "type" "multi")]) +(define_insn "*return_losum_si" + [(set (match_operand:SI 0 "restore_operand" "") + (lo_sum:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "immediate_operand" "in"))) + (return)] + "! TARGET_EPILOGUE && ! TARGET_LIVE_G0 && ! TARGET_CM_MEDMID" + "* +{ + if (! TARGET_ARCH64 && current_function_returns_struct) + return \"jmp\\t%%i7+12\\n\\trestore %r1, %%lo(%a2), %Y0\"; + /* If operands are global or in registers, can use return */ + else if (TARGET_V9 && IN_OR_GLOBAL_P (operands[1])) + return \"return\\t%%i7+8\\n\\tor\\t%Y1, %%lo(%a2), %Y0\"; + else + return \"ret\;restore %r1, %%lo(%a2), %Y0\"; +}" + [(set_attr "type" "multi")]) + (define_insn "*return_di" [(set (match_operand:DI 0 "restore_operand" "") (match_operand:DI 1 "arith_double_operand" "rHI")) @@ -8208,6 +8226,15 @@ "ret\;restore %r1, %2, %Y0" [(set_attr "type" "multi")]) +(define_insn "*return_losum_di" + [(set (match_operand:DI 0 "restore_operand" "") + (lo_sum:DI (match_operand:DI 1 "arith_operand" "%r") + (match_operand:DI 2 "immediate_operand" "in"))) + (return)] + "TARGET_ARCH64 && ! TARGET_EPILOGUE && ! TARGET_CM_MEDMID" + "ret\;restore %r1, %%lo(a2), %Y0" + [(set_attr "type" "multi")]) + ;; The following pattern is only generated by delayed-branch scheduling, ;; when the insn winds up in the epilogue. (define_insn "*return_sf" -- 2.7.4