From b166356e0aae66eb9affc05c891d8cf851728186 Mon Sep 17 00:00:00 2001 From: aoliva Date: Thu, 10 Jul 2003 02:56:29 +0000 Subject: [PATCH] * config/mn10300/mn10300.h (PREDICATE_CODES): Define. 2001-05-01 Alexandre Oliva * config/mn10300/mn10300.md (sqrtsf2): flag_fast_math was renamed to flag_unsafe_math_optimizations. 2001-04-14 Alexandre Oliva * config/mn10300/mn10300.c (expand_prologue): Mark FP-register-saving insns as frame-related. 2001-02-13 Alexandre Oliva * config/mn10300/mn10300.c (mn10300_get_live_callee_saved_regs): Don't search past LAST_EXTENDED_REGNUM. (mn10300_gen_multiple_store, store_multiple_operation): Likewise. * config/mn10300/mn10300.md: Remove excessive line breaks from `@' output patterns that were accounted as additional alternatives. * config/mn10300/mn10300.md, config/mn10300/mn10300.c: Re-introduce changes accidentally removed in Richard Sandiford's 2000-12-05's patch. * config/mn10300/t-mn10300 (MULTILIB_OPTIONS, MULTILIB_DIRNAMES): Re-instate am33-2 lost in merge from net GCC. 2000-08-26 Alexandre Oliva * config/mn10300/mn10300.h (DBX_REGISTER_NUMBER): Added floating-point registers. 2000-08-07 Alexandre Oliva * config/mn10300/mn10300.md (movdf): Revert some am33-specific pessimizations that had gone in on 2000-05-08. 2000-06-28 Graham Stott * config/mn10300/mn10300.h (REG_CLASS_CONTENTS): Fix typo. 2000-06-22 Graham Stott * config/mn10300/mn10300.md (movqi): Use nonimmediate_operand for operand 0. * (movhi): Likewise. * (movsi): Likewise. * (movsf): Likewise. * (movdi): Likewise. * (movdf): Likewise. Wed May 24 13:16:09 2000 Alexandre Oliva * config/mn10300/mn10300.c (fp_regs_to_save): New function. (can_use_return_insn, initial_offset): Add fp_regs_to_save. (expand_prologue, expand_epilogue): Save and restore FP regs. 2000-05-20 Alexandre Oliva * config/mn10300/mn10300.md (movdi, movdf): 64-bit clean-up. 2000-05-13 Alexandre Oliva * config/mn10300/mn10300.md (abssf2, negsf2, rsqrtsf2, addsf3, subsf3, mulsf3, divsf3, fmaddsf4, fmsubsf4, fnmaddsf4, fnmsubsf4): Do not clobber cc0. 2000-05-12 Alexandre Oliva * config/mn10300/mn10300.md (abssf2, negsf2, rsqrtsf2): Discourage the two-argument, longer opcodes. (addsf3, subsf3, mulsf3, divsf3): Likewise for three-argument ones. * config/mn10300/mn10300.h (struct mn10300_cc_status_mdep): New. (CC_STATUS_MDEP, CC_STATUS_MDEP_INIT): Define. * config/mn10300/mn10300.md (cmpsf): New pattern. (branch): Test mdep.fpCC and output fbCC. * config/mn10300/mn10300.c (print_operand): Output conditions. (notice_cc_update): Recognize fcmp and set mdep.fpCC. 2000-05-10 Alexandre Oliva * config/mn10300/mn10300.md (movsf, movdf, addsf3, subsf3, mulsf3, divsf3): Use the `F' constraint for FP values. * config/mn10300/mn10300.c (const_1f_operand): New function. * config/mn10300/mn10300-protos.h (const_1f_operand): Declare. * config/mn10300/mn10300.md (sqrtsf2): New expand. (rsqrtsf2): New insn. 2000-05-09 Alexandre Oliva * config/mn10300/mn10300.md (movdf): Oops, I missed it in my previous check-in. 2000-05-08 Alexandre Oliva * config/mn10300/mn10300.md (abssf2, negdf2): On TARGET_AM33_2, expand to... (abssf2_am33_2, negdf2_am33_2): New insns. (addsf3, subsf3, mulsf3, divsf3): Likewise. (fmaddsf4, fmsubsf4, fnmaddsf4, fnmsubsf4): Likewise. * config/mn10300/mn10300.md (movqi, movhi, movsi, movsf, movdi, movdf): Added FP regs. * invoke.texi (-mam33-2, -mno-am33-2): Document. 2000-04-29 Alexandre Oliva * config/mn10300/mn10300.h (FIRST_FP_REGNUM, LAST_FP_REGNUM): New macros. (REGNO_AM33_2_FP_P): Renamed to... (REGNO_FP_P): Redefine in terms of FIRST_* and LAST_*. (CONDITIONAL_REGISTER_USAGE, REGNO_REG_CLASS): Likewise. 2000-04-27 Alexandre Oliva * config/mn10300/mn10300.h (REG_CLASS_CONTENTS): Remove FP regs from GENERAL_REGS. 2000-04-27 Alexandre Oliva * config/mn10300/mn10300.h (REGNO_AM33_2_FP_P): New macro. * config/mn10300/mn10300.c (mn10300_address_cost): Added FP_REGS. * config/mn10300/mn10300.h (REGISTER_MOVE_COST): Added FP_REGS. 2000-04-23 Alexandre Oliva * config/mn10300/mn10300.h (CLASS_CANNOT_CHANGE_SIZE): Defined as FP_REGS. 2000-04-21 Alexandre Oliva * config/mn10300/mn10300.h (OK_FOR_Q): New macro. (EXTRA_CONSTRAINT): Added OK_FOR_Q. * config/mn10300/mn10300.c (secondary_reload_class): Adjust. * config/mn10300/mn10300.c (print_operand): Support `D' for doubles. * config/mn10300/mn10300.h (FIRST_PSEUDO_REGISTER): Adjust. (FIXED_REGISTERS, CALL_USED_REGISTERS, REG_ALLOC_ORDER): Added AM33/2.0 floating-point registers. (CONDITIONAL_REGISTER_USAGE): Adjust. (enum reg_class, REG_CLASS_NAMES): Added FP_REGS and FP_ACC_REGS. (REG_CLASS_CONTENTS, REGNO_REG_CLASS): Adjust. (REG_CLASS_FROM_LETTER): Added `f' and `A'. (REGISTER_NAMES, ADDITIONAL_REGISTER_NAMES): Adjust. * config/mn10300/t-mn10300 (MULTILIB_OPTIONS): Added am33-2. (MULTILIB_DIRNAMES): Likewise. * config/mn10300/mn10300.h (CPP_SPEC): Define `__AM33__=2' and `__AM33_2__' when `-mam33-2' is given. (TARGET_AM33_2): Define. (TARGET_SWITCHES): Adjust. * config/mn10300/mn10300.c (asm_file_start): Print `.am33_2' when appropriate. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@69167 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 116 +++++++++ gcc/config/mn10300/mn10300.c | 547 +++++++++++++++++++++++++++++++++++++++++- gcc/config/mn10300/mn10300.h | 102 ++++++-- gcc/config/mn10300/mn10300.md | 264 +++++++++++++++++--- gcc/config/mn10300/t-mn10300 | 4 +- gcc/doc/invoke.texi | 1 + 6 files changed, 975 insertions(+), 59 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6bf663b85c2..d01693a4213 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,119 @@ +2003-07-09 Alexandre Oliva + + * config/mn10300/mn10300.h (PREDICATE_CODES): Define. + 2001-05-01 Alexandre Oliva + * config/mn10300/mn10300.md (sqrtsf2): flag_fast_math was renamed + to flag_unsafe_math_optimizations. + 2001-04-14 Alexandre Oliva + * config/mn10300/mn10300.c (expand_prologue): Mark + FP-register-saving insns as frame-related. + 2001-02-13 Alexandre Oliva + * config/mn10300/mn10300.c + (mn10300_get_live_callee_saved_regs): Don't search past + LAST_EXTENDED_REGNUM. + (mn10300_gen_multiple_store, store_multiple_operation): Likewise. + * config/mn10300/mn10300.md: Remove excessive line breaks from + `@' output patterns that were accounted as additional + alternatives. + * config/mn10300/mn10300.md, config/mn10300/mn10300.c: + Re-introduce changes accidentally removed in Richard Sandiford's + 2000-12-05's patch. + * config/mn10300/t-mn10300 (MULTILIB_OPTIONS, MULTILIB_DIRNAMES): + Re-instate am33-2 lost in merge from net GCC. + 2000-08-26 Alexandre Oliva + * config/mn10300/mn10300.h (DBX_REGISTER_NUMBER): Added + floating-point registers. + 2000-08-07 Alexandre Oliva + * config/mn10300/mn10300.md (movdf): Revert some am33-specific + pessimizations that had gone in on 2000-05-08. + 2000-06-28 Graham Stott + * config/mn10300/mn10300.h (REG_CLASS_CONTENTS): Fix typo. + 2000-06-22 Graham Stott + * config/mn10300/mn10300.md (movqi): Use nonimmediate_operand for + operand 0. + * (movhi): Likewise. + * (movsi): Likewise. + * (movsf): Likewise. + * (movdi): Likewise. + * (movdf): Likewise. + Wed May 24 13:16:09 2000 Alexandre Oliva + * config/mn10300/mn10300.c (fp_regs_to_save): New function. + (can_use_return_insn, initial_offset): Add fp_regs_to_save. + (expand_prologue, expand_epilogue): Save and restore FP regs. + 2000-05-20 Alexandre Oliva + * config/mn10300/mn10300.md (movdi, movdf): 64-bit clean-up. + 2000-05-13 Alexandre Oliva + * config/mn10300/mn10300.md (abssf2, negsf2, rsqrtsf2, addsf3, + subsf3, mulsf3, divsf3, fmaddsf4, fmsubsf4, fnmaddsf4, fnmsubsf4): + Do not clobber cc0. + 2000-05-12 Alexandre Oliva + * config/mn10300/mn10300.md (abssf2, negsf2, rsqrtsf2): + Discourage the two-argument, longer opcodes. + (addsf3, subsf3, mulsf3, divsf3): Likewise for three-argument + ones. + * config/mn10300/mn10300.h (struct mn10300_cc_status_mdep): New. + (CC_STATUS_MDEP, CC_STATUS_MDEP_INIT): Define. + * config/mn10300/mn10300.md (cmpsf): New pattern. + (branch): Test mdep.fpCC and output fbCC. + * config/mn10300/mn10300.c (print_operand): Output conditions. + (notice_cc_update): Recognize fcmp and set mdep.fpCC. + 2000-05-10 Alexandre Oliva + * config/mn10300/mn10300.md (movsf, movdf, addsf3, subsf3, + mulsf3, divsf3): Use the `F' constraint for FP values. + * config/mn10300/mn10300.c (const_1f_operand): New function. + * config/mn10300/mn10300-protos.h (const_1f_operand): Declare. + * config/mn10300/mn10300.md (sqrtsf2): New expand. + (rsqrtsf2): New insn. + 2000-05-09 Alexandre Oliva + * config/mn10300/mn10300.md (movdf): Oops, I missed it in my + previous check-in. + 2000-05-08 Alexandre Oliva + * config/mn10300/mn10300.md (abssf2, negdf2): On + TARGET_AM33_2, expand to... + (abssf2_am33_2, negdf2_am33_2): New insns. + (addsf3, subsf3, mulsf3, divsf3): Likewise. + (fmaddsf4, fmsubsf4, fnmaddsf4, fnmsubsf4): Likewise. + * config/mn10300/mn10300.md (movqi, movhi, movsi, movsf, + movdi, movdf): Added FP regs. + * invoke.texi (-mam33-2, -mno-am33-2): Document. + 2000-04-29 Alexandre Oliva + * config/mn10300/mn10300.h (FIRST_FP_REGNUM, LAST_FP_REGNUM): + New macros. + (REGNO_AM33_2_FP_P): Renamed to... + (REGNO_FP_P): Redefine in terms of FIRST_* and LAST_*. + (CONDITIONAL_REGISTER_USAGE, REGNO_REG_CLASS): Likewise. + 2000-04-27 Alexandre Oliva + * config/mn10300/mn10300.h (REG_CLASS_CONTENTS): Remove FP + regs from GENERAL_REGS. + 2000-04-27 Alexandre Oliva + * config/mn10300/mn10300.h (REGNO_AM33_2_FP_P): New macro. + * config/mn10300/mn10300.c (mn10300_address_cost): Added FP_REGS. + * config/mn10300/mn10300.h (REGISTER_MOVE_COST): Added FP_REGS. + 2000-04-23 Alexandre Oliva + * config/mn10300/mn10300.h (CLASS_CANNOT_CHANGE_SIZE): Defined + as FP_REGS. + 2000-04-21 Alexandre Oliva + * config/mn10300/mn10300.h (OK_FOR_Q): New macro. + (EXTRA_CONSTRAINT): Added OK_FOR_Q. + * config/mn10300/mn10300.c (secondary_reload_class): Adjust. + * config/mn10300/mn10300.c (print_operand): Support `D' for doubles. + * config/mn10300/mn10300.h (FIRST_PSEUDO_REGISTER): Adjust. + (FIXED_REGISTERS, CALL_USED_REGISTERS, REG_ALLOC_ORDER): Added + AM33/2.0 floating-point registers. + (CONDITIONAL_REGISTER_USAGE): Adjust. + (enum reg_class, REG_CLASS_NAMES): Added FP_REGS and FP_ACC_REGS. + (REG_CLASS_CONTENTS, REGNO_REG_CLASS): Adjust. + (REG_CLASS_FROM_LETTER): Added `f' and `A'. + (REGISTER_NAMES, ADDITIONAL_REGISTER_NAMES): Adjust. + * config/mn10300/t-mn10300 (MULTILIB_OPTIONS): Added am33-2. + (MULTILIB_DIRNAMES): Likewise. + * config/mn10300/mn10300.h (CPP_SPEC): Define `__AM33__=2' and + `__AM33_2__' when `-mam33-2' is given. + (TARGET_AM33_2): Define. + (TARGET_SWITCHES): Adjust. + * config/mn10300/mn10300.c (asm_file_start): Print `.am33_2' + when appropriate. + 2003-07-09 Matt Kraai * doc/install.texi: Add missing @. diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c index df5d35fb770..bb14b4c9023 100644 --- a/gcc/config/mn10300/mn10300.c +++ b/gcc/config/mn10300/mn10300.c @@ -82,7 +82,9 @@ mn10300_file_start () { default_file_start (); - if (TARGET_AM33) + if (TARGET_AM33_2) + fprintf (asm_out_file, "\t.am33_2\n"); + else if (TARGET_AM33) fprintf (asm_out_file, "\t.am33\n"); } @@ -100,6 +102,58 @@ print_operand (file, x, code) { case 'b': case 'B': + if (cc_status.mdep.fpCC) + { + switch (code == 'b' ? GET_CODE (x) + : reverse_condition_maybe_unordered (GET_CODE (x))) + { + case NE: + fprintf (file, "ne"); + break; + case EQ: + fprintf (file, "eq"); + break; + case GE: + fprintf (file, "ge"); + break; + case GT: + fprintf (file, "gt"); + break; + case LE: + fprintf (file, "le"); + break; + case LT: + fprintf (file, "lt"); + break; + case ORDERED: + fprintf (file, "lge"); + break; + case UNORDERED: + fprintf (file, "uo"); + break; + case LTGT: + fprintf (file, "lg"); + break; + case UNEQ: + fprintf (file, "ue"); + break; + case UNGE: + fprintf (file, "uge"); + break; + case UNGT: + fprintf (file, "ug"); + break; + case UNLE: + fprintf (file, "ule"); + break; + case UNLT: + fprintf (file, "ul"); + break; + default: + abort (); + } + break; + } /* These are normal and reversed branches. */ switch (code == 'b' ? GET_CODE (x) : reverse_condition (GET_CODE (x))) { @@ -151,6 +205,24 @@ print_operand (file, x, code) print_operand (file, x, 0); break; + case 'D': + switch (GET_CODE (x)) + { + case MEM: + fputc ('(', file); + output_address (XEXP (x, 0)); + fputc (')', file); + break; + + case REG: + fprintf (file, "fd%d", REGNO (x) - 18); + break; + + default: + abort (); + } + break; + /* These are the least significant word in a 64bit value. */ case 'L': switch (GET_CODE (x)) @@ -388,6 +460,22 @@ print_operand_address (file, addr) } } +/* Count the number of FP registers that have to be saved. */ +static int +fp_regs_to_save () +{ + int i, n = 0; + + if (! TARGET_AM33_2) + return 0; + + for (i = FIRST_FP_REGNUM; i <= LAST_FP_REGNUM; ++i) + if (regs_ever_live[i] && ! call_used_regs[i]) + ++n; + + return n; +} + /* Print a set of registers in the format required by "movm" and "ret". Register K is saved if bit K of MASK is set. The data and address registers can be stored individually, but the extended registers cannot. @@ -446,6 +534,7 @@ can_use_return_insn () && !regs_ever_live[15] && !regs_ever_live[16] && !regs_ever_live[17] + && fp_regs_to_save () == 0 && !frame_pointer_needed); } @@ -460,7 +549,7 @@ mn10300_get_live_callee_saved_regs () int i; mask = 0; - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + for (i = 0; i <= LAST_EXTENDED_REGNUM; i++) if (regs_ever_live[i] && ! call_used_regs[i]) mask |= (1 << i); if ((mask & 0x3c000) != 0) @@ -501,7 +590,7 @@ mn10300_gen_multiple_store (mask) /* Count how many registers need to be saved. */ count = 0; - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + for (i = 0; i <= LAST_EXTENDED_REGNUM; i++) if ((mask & (1 << i)) != 0) count += 1; @@ -519,7 +608,7 @@ mn10300_gen_multiple_store (mask) /* Create each store. */ pari = 1; - for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--) + for (i = LAST_EXTENDED_REGNUM; i >= 0; i--) if ((mask & (1 << i)) != 0) { rtx address = gen_rtx_PLUS (SImode, @@ -549,6 +638,240 @@ expand_prologue () /* If we use any of the callee-saved registers, save them now. */ mn10300_gen_multiple_store (mn10300_get_live_callee_saved_regs ()); + if (TARGET_AM33_2 && fp_regs_to_save ()) + { + int num_regs_to_save = fp_regs_to_save (), i; + HOST_WIDE_INT xsize; + enum { save_sp_merge, + save_sp_no_merge, + save_sp_partial_merge, + save_a0_merge, + save_a0_no_merge } strategy; + unsigned int strategy_size = (unsigned)-1, this_strategy_size; + rtx reg; + rtx insn; + + /* We have several different strategies to save FP registers. + We can store them using SP offsets, which is beneficial if + there are just a few registers to save, or we can use `a0' in + post-increment mode (`a0' is the only call-clobbered address + register that is never used to pass information to a + function). Furthermore, if we don't need a frame pointer, we + can merge the two SP adds into a single one, but this isn't + always beneficial; sometimes we can just split the two adds + so that we don't exceed a 16-bit constant size. The code + below will select which strategy to use, so as to generate + smallest code. Ties are broken in favor or shorter sequences + (in terms of number of instructions). */ + +#define SIZE_ADD_AX(S) ((((S) >= (1 << 15)) || ((S) < -(1 << 15))) ? 6 \ + : (((S) >= (1 << 7)) || ((S) < -(1 << 7))) ? 4 : 2) +#define SIZE_ADD_SP(S) ((((S) >= (1 << 15)) || ((S) < -(1 << 15))) ? 6 \ + : (((S) >= (1 << 7)) || ((S) < -(1 << 7))) ? 4 : 3) +#define SIZE_FMOV_LIMIT(S,N,L,SIZE1,SIZE2,ELSE) \ + (((S) >= (L)) ? (SIZE1) * (N) \ + : ((S) + 4 * (N) >= (L)) ? (((L) - (S)) / 4 * (SIZE2) \ + + ((S) + 4 * (N) - (L)) / 4 * (SIZE1)) \ + : (ELSE)) +#define SIZE_FMOV_SP_(S,N) \ + (SIZE_FMOV_LIMIT ((S), (N), (1 << 24), 7, 6, \ + SIZE_FMOV_LIMIT ((S), (N), (1 << 8), 6, 4, \ + (S) ? 4 * (N) : 3 + 4 * ((N) - 1)))) +#define SIZE_FMOV_SP(S,N) (SIZE_FMOV_SP_ ((unsigned HOST_WIDE_INT)(S), (N))) + + /* Consider alternative save_sp_merge only if we don't need the + frame pointer and size is non-zero. */ + if (! frame_pointer_needed && size) + { + /* Insn: add -(size + 4 * num_regs_to_save), sp. */ + this_strategy_size = SIZE_ADD_SP (-(size + 4 * num_regs_to_save)); + /* Insn: fmov fs#, (##, sp), for each fs# to be saved. */ + this_strategy_size += SIZE_FMOV_SP (size, num_regs_to_save); + + if (this_strategy_size < strategy_size) + { + strategy = save_sp_merge; + strategy_size = this_strategy_size; + } + } + + /* Consider alternative save_sp_no_merge unconditionally. */ + /* Insn: add -4 * num_regs_to_save, sp. */ + this_strategy_size = SIZE_ADD_SP (-4 * num_regs_to_save); + /* Insn: fmov fs#, (##, sp), for each fs# to be saved. */ + this_strategy_size += SIZE_FMOV_SP (0, num_regs_to_save); + if (size) + { + /* Insn: add -size, sp. */ + this_strategy_size += SIZE_ADD_SP (-size); + } + + if (this_strategy_size < strategy_size) + { + strategy = save_sp_no_merge; + strategy_size = this_strategy_size; + } + + /* Consider alternative save_sp_partial_merge only if we don't + need a frame pointer and size is reasonably large. */ + if (! frame_pointer_needed && size + 4 * num_regs_to_save > 128) + { + /* Insn: add -128, sp. */ + this_strategy_size = SIZE_ADD_SP (-128); + /* Insn: fmov fs#, (##, sp), for each fs# to be saved. */ + this_strategy_size += SIZE_FMOV_SP (128 - 4 * num_regs_to_save, + num_regs_to_save); + if (size) + { + /* Insn: add 128-size, sp. */ + this_strategy_size += SIZE_ADD_SP (128 - size); + } + + if (this_strategy_size < strategy_size) + { + strategy = save_sp_partial_merge; + strategy_size = this_strategy_size; + } + } + + /* Consider alternative save_a0_merge only if we don't need a + frame pointer, size is non-zero and the user hasn't + changed the calling conventions of a0. */ + if (! frame_pointer_needed && size + && call_used_regs[FIRST_ADDRESS_REGNUM] + && ! fixed_regs[FIRST_ADDRESS_REGNUM]) + { + /* Insn: add -(size + 4 * num_regs_to_save), sp. */ + this_strategy_size = SIZE_ADD_SP (-(size + 4 * num_regs_to_save)); + /* Insn: mov sp, a0. */ + this_strategy_size++; + if (size) + { + /* Insn: add size, a0. */ + this_strategy_size += SIZE_ADD_AX (size); + } + /* Insn: fmov fs#, (a0+), for each fs# to be saved. */ + this_strategy_size += 3 * num_regs_to_save; + + if (this_strategy_size < strategy_size) + { + strategy = save_a0_merge; + strategy_size = this_strategy_size; + } + } + + /* Consider alternative save_a0_no_merge if the user hasn't + changed the calling conventions of a0. */ + if (call_used_regs[FIRST_ADDRESS_REGNUM] + && ! fixed_regs[FIRST_ADDRESS_REGNUM]) + { + /* Insn: add -4 * num_regs_to_save, sp. */ + this_strategy_size = SIZE_ADD_SP (-4 * num_regs_to_save); + /* Insn: mov sp, a0. */ + this_strategy_size++; + /* Insn: fmov fs#, (a0+), for each fs# to be saved. */ + this_strategy_size += 3 * num_regs_to_save; + if (size) + { + /* Insn: add -size, sp. */ + this_strategy_size += SIZE_ADD_SP (-size); + } + + if (this_strategy_size < strategy_size) + { + strategy = save_a0_no_merge; + strategy_size = this_strategy_size; + } + } + + /* Emit the initial SP add, common to all strategies. */ + switch (strategy) + { + case save_sp_no_merge: + case save_a0_no_merge: + emit_insn (gen_addsi3 (stack_pointer_rtx, + stack_pointer_rtx, + GEN_INT (-4 * num_regs_to_save))); + xsize = 0; + break; + + case save_sp_partial_merge: + emit_insn (gen_addsi3 (stack_pointer_rtx, + stack_pointer_rtx, + GEN_INT (-128))); + xsize = 128 - 4 * num_regs_to_save; + size -= xsize; + break; + + case save_sp_merge: + case save_a0_merge: + emit_insn (gen_addsi3 (stack_pointer_rtx, + stack_pointer_rtx, + GEN_INT (-(size + 4 * num_regs_to_save)))); + /* We'll have to adjust FP register saves according to the + frame size. */ + xsize = size; + /* Since we've already created the stack frame, don't do it + again at the end of the function. */ + size = 0; + break; + + default: + abort (); + } + + /* Now prepare register a0, if we have decided to use it. */ + switch (strategy) + { + case save_sp_merge: + case save_sp_no_merge: + case save_sp_partial_merge: + reg = 0; + break; + + case save_a0_merge: + case save_a0_no_merge: + reg = gen_rtx_REG (SImode, FIRST_ADDRESS_REGNUM); + emit_insn (gen_movsi (reg, stack_pointer_rtx)); + if (xsize) + emit_insn (gen_addsi3 (reg, reg, GEN_INT (xsize))); + reg = gen_rtx_POST_INC (SImode, reg); + break; + + default: + abort (); + } + + /* Now actually save the FP registers. */ + for (i = FIRST_FP_REGNUM; i <= LAST_FP_REGNUM; ++i) + if (regs_ever_live[i] && ! call_used_regs[i]) + { + rtx addr; + + if (reg) + addr = reg; + else + { + /* If we aren't using `a0', use an SP offset. */ + if (xsize) + { + addr = gen_rtx_PLUS (SImode, + stack_pointer_rtx, + GEN_INT (xsize)); + } + else + addr = stack_pointer_rtx; + + xsize += 4; + } + + insn = emit_insn (gen_movsi (gen_rtx_MEM (SImode, addr), + gen_rtx_REG (SImode, i))); + + RTX_FRAME_RELATED_P (insn) = 1; + } + } + /* Now put the frame pointer into the frame pointer register. */ if (frame_pointer_needed) emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); @@ -569,6 +892,193 @@ expand_epilogue () size = get_frame_size () + current_function_outgoing_args_size; size += (current_function_outgoing_args_size ? 4 : 0); + if (TARGET_AM33_2 && fp_regs_to_save ()) + { + int num_regs_to_save = fp_regs_to_save (), i; + rtx reg = 0; + + /* We have several options to restore FP registers. We could + load them from SP offsets, but, if there are enough FP + registers to restore, we win if we use a post-increment + addressing mode. */ + + /* If we have a frame pointer, it's the best option, because we + already know it has the value we want. */ + if (frame_pointer_needed) + reg = gen_rtx_REG (SImode, FRAME_POINTER_REGNUM); + /* Otherwise, we may use `a1', since it's call-clobbered and + it's never used for return values. But only do so if it's + smaller than using SP offsets. */ + else + { + enum { restore_sp_post_adjust, + restore_sp_pre_adjust, + restore_sp_partial_adjust, + restore_a1 } strategy; + unsigned int this_strategy_size, strategy_size = (unsigned)-1; + + /* Consider using sp offsets before adjusting sp. */ + /* Insn: fmov (##,sp),fs#, for each fs# to be restored. */ + this_strategy_size = SIZE_FMOV_SP (size, num_regs_to_save); + /* If size is too large, we'll have to adjust SP with an + add. */ + if (size + 4 * num_regs_to_save + REG_SAVE_BYTES > 255) + { + /* Insn: add size + 4 * num_regs_to_save, sp. */ + this_strategy_size += SIZE_ADD_SP (size + 4 * num_regs_to_save); + } + /* If we don't have to restore any non-FP registers, + we'll be able to save one byte by using rets. */ + if (! REG_SAVE_BYTES) + this_strategy_size--; + + if (this_strategy_size < strategy_size) + { + strategy = restore_sp_post_adjust; + strategy_size = this_strategy_size; + } + + /* Consider using sp offsets after adjusting sp. */ + /* Insn: add size, sp. */ + this_strategy_size = SIZE_ADD_SP (size); + /* Insn: fmov (##,sp),fs#, for each fs# to be restored. */ + this_strategy_size += SIZE_FMOV_SP (0, num_regs_to_save); + /* We're going to use ret to release the FP registers + save area, so, no savings. */ + + if (this_strategy_size < strategy_size) + { + strategy = restore_sp_pre_adjust; + strategy_size = this_strategy_size; + } + + /* Consider using sp offsets after partially adjusting sp. + When size is close to 32Kb, we may be able to adjust SP + with an imm16 add instruction while still using fmov + (d8,sp). */ + if (size + 4 * num_regs_to_save + REG_SAVE_BYTES > 255) + { + /* Insn: add size + 4 * num_regs_to_save + + REG_SAVE_BYTES - 252,sp. */ + this_strategy_size = SIZE_ADD_SP (size + 4 * num_regs_to_save + + REG_SAVE_BYTES - 252); + /* Insn: fmov (##,sp),fs#, fo each fs# to be restored. */ + this_strategy_size += SIZE_FMOV_SP (252 - REG_SAVE_BYTES + - 4 * num_regs_to_save, + num_regs_to_save); + /* We're going to use ret to release the FP registers + save area, so, no savings. */ + + if (this_strategy_size < strategy_size) + { + strategy = restore_sp_partial_adjust; + strategy_size = this_strategy_size; + } + } + + /* Consider using a1 in post-increment mode, as long as the + user hasn't changed the calling conventions of a1. */ + if (call_used_regs[FIRST_ADDRESS_REGNUM+1] + && ! fixed_regs[FIRST_ADDRESS_REGNUM+1]) + { + /* Insn: mov sp,a1. */ + this_strategy_size = 1; + if (size) + { + /* Insn: add size,a1. */ + this_strategy_size += SIZE_ADD_AX (size); + } + /* Insn: fmov (a1+),fs#, for each fs# to be restored. */ + this_strategy_size += 3 * num_regs_to_save; + /* If size is large enough, we may be able to save a + couple of bytes. */ + if (size + 4 * num_regs_to_save + REG_SAVE_BYTES > 255) + { + /* Insn: mov a1,sp. */ + this_strategy_size += 2; + } + /* If we don't have to restore any non-FP registers, + we'll be able to save one byte by using rets. */ + if (! REG_SAVE_BYTES) + this_strategy_size--; + + if (this_strategy_size < strategy_size) + { + strategy = restore_a1; + strategy_size = this_strategy_size; + } + } + + switch (strategy) + { + case restore_sp_post_adjust: + break; + + case restore_sp_pre_adjust: + emit_insn (gen_addsi3 (stack_pointer_rtx, + stack_pointer_rtx, + GEN_INT (size))); + size = 0; + break; + + case restore_sp_partial_adjust: + emit_insn (gen_addsi3 (stack_pointer_rtx, + stack_pointer_rtx, + GEN_INT (size + 4 * num_regs_to_save + + REG_SAVE_BYTES - 252))); + size = 252 - REG_SAVE_BYTES - 4 * num_regs_to_save; + break; + + case restore_a1: + reg = gen_rtx_REG (SImode, FIRST_ADDRESS_REGNUM + 1); + emit_insn (gen_movsi (reg, stack_pointer_rtx)); + if (size) + emit_insn (gen_addsi3 (reg, reg, GEN_INT (size))); + break; + + default: + abort (); + } + } + + /* Adjust the selected register, if any, for post-increment. */ + if (reg) + reg = gen_rtx_POST_INC (SImode, reg); + + for (i = FIRST_FP_REGNUM; i <= LAST_FP_REGNUM; ++i) + if (regs_ever_live[i] && ! call_used_regs[i]) + { + rtx addr; + + if (reg) + addr = reg; + else if (size) + { + /* If we aren't using a post-increment register, use an + SP offset. */ + addr = gen_rtx_PLUS (SImode, + stack_pointer_rtx, + GEN_INT (size)); + } + else + addr = stack_pointer_rtx; + + size += 4; + + emit_insn (gen_movsi (gen_rtx_REG (SImode, i), + gen_rtx_MEM (SImode, addr))); + } + + /* If we were using the restore_a1 strategy and the number of + bytes to be released won't fit in the `ret' byte, copy `a1' + to `sp', to avoid having to use `add' to adjust it. */ + if (! frame_pointer_needed && reg && size + REG_SAVE_BYTES > 255) + { + emit_move_insn (stack_pointer_rtx, XEXP (reg, 0)); + size = 0; + } + } + /* Maybe cut back the stack, except for the register save area. If the frame pointer exists, then use the frame pointer to @@ -649,6 +1159,9 @@ notice_update_cc (body, insn) /* The insn is a compare instruction. */ CC_STATUS_INIT; cc_status.value1 = SET_SRC (body); + if (GET_CODE (cc_status.value1) == COMPARE + && GET_MODE (XEXP (cc_status.value1, 0)) == SFmode) + cc_status.mdep.fpCC = 1; break; case CC_INVERT: @@ -714,7 +1227,7 @@ store_multiple_operation (op, mode) LAST keeps track of the smallest-numbered register stored so far. MASK is the set of stored registers. */ - last = FIRST_PSEUDO_REGISTER; + last = LAST_EXTENDED_REGNUM + 1; mask = 0; for (i = 1; i < count; i++) { @@ -810,6 +1323,14 @@ secondary_reload_class (class, mode, in) return DATA_REGS; } + if (TARGET_AM33_2 && class == FP_REGS + && GET_CODE (in) == MEM && ! OK_FOR_Q (in)) + { + if (TARGET_AM33) + return DATA_OR_EXTENDED_REGS; + return DATA_REGS; + } + /* Otherwise assume no secondary reloads are needed. */ return NO_REGS; } @@ -826,8 +1347,10 @@ initial_offset (from, to) || regs_ever_live[6] || regs_ever_live[7] || regs_ever_live[14] || regs_ever_live[15] || regs_ever_live[16] || regs_ever_live[17] + || fp_regs_to_save () || frame_pointer_needed) - return REG_SAVE_BYTES; + return REG_SAVE_BYTES + + 4 * fp_regs_to_save (); else return 0; } @@ -841,8 +1364,10 @@ initial_offset (from, to) || regs_ever_live[6] || regs_ever_live[7] || regs_ever_live[14] || regs_ever_live[15] || regs_ever_live[16] || regs_ever_live[17] + || fp_regs_to_save () || frame_pointer_needed) return (get_frame_size () + REG_SAVE_BYTES + + 4 * fp_regs_to_save () + (current_function_outgoing_args_size ? current_function_outgoing_args_size + 4 : 0)); else @@ -1155,6 +1680,15 @@ const_8bit_operand (op, mode) && INTVAL (op) < 256); } +/* Return true if the operand is the 1.0f constant. */ +int +const_1f_operand (op, mode) + register rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + return (op == CONST1_RTX (SFmode)); +} + /* Similarly, but when using a zero_extract pattern for a btst where the source operand might end up in memory. */ int @@ -1271,6 +1805,7 @@ mn10300_address_cost_1 (x, unsig) case DATA_REGS: case EXTENDED_REGS: + case FP_REGS: return 3; case NO_REGS: diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h index cae8f2a3f81..75d4183af74 100644 --- a/gcc/config/mn10300/mn10300.h +++ b/gcc/config/mn10300/mn10300.h @@ -1,6 +1,6 @@ /* Definitions of target machine for GNU compiler. Matsushita MN10300 series - Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Contributed by Jeff Law (law@cygnus.com). @@ -40,7 +40,7 @@ Boston, MA 02111-1307, USA. */ } \ while (0) -#define CPP_SPEC "%{mam33:-D__AM33__}" +#define CPP_SPEC "%{mam33:-D__AM33__} %{mam33-2:-D__AM33__=2 -D__AM33_2__}" /* Run-time compilation parameters selecting different hardware subsets. */ @@ -60,6 +60,9 @@ extern int target_flags; /* Generate code for the AM33 processor. */ #define TARGET_AM33 (target_flags & 0x2) +/* Generate code for the AM33/2.0 processor. */ +#define TARGET_AM33_2 (target_flags & 0x4) + #define TARGET_SWITCHES \ {{ "mult-bug", 0x1, N_("Work around hardware multiply bug")}, \ { "no-mult-bug", -0x1, N_("Do not work around hardware multiply bug")},\ @@ -67,6 +70,9 @@ extern int target_flags; { "am33", -(0x1), ""},\ { "no-am33", -0x2, ""}, \ { "no-crt0", 0, N_("No default crt0.o") }, \ + { "am33-2", 0x6, N_("Target the AM33/2.0 processor")}, \ + { "am33-2", -(0x1), ""},\ + { "no-am33-2", -0x4, ""}, \ { "relax", 0, N_("Enable linker relaxations") }, \ { "", TARGET_DEFAULT, NULL}} @@ -131,7 +137,7 @@ extern int target_flags; All registers that the compiler knows about must be given numbers, even those that are not normally considered general registers. */ -#define FIRST_PSEUDO_REGISTER 18 +#define FIRST_PSEUDO_REGISTER 50 /* Specify machine-specific register numbers. */ #define FIRST_DATA_REGNUM 0 @@ -140,6 +146,8 @@ extern int target_flags; #define LAST_ADDRESS_REGNUM 8 #define FIRST_EXTENDED_REGNUM 10 #define LAST_EXTENDED_REGNUM 17 +#define FIRST_FP_REGNUM 18 +#define LAST_FP_REGNUM 49 /* Specify the registers used for certain standard purposes. The values of these macros are register numbers. */ @@ -162,7 +170,10 @@ extern int target_flags; and are not available for the register allocator. */ #define FIXED_REGISTERS \ - { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0} + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 \ + , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ + , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ + } /* 1 for registers not available across function calls. These must include the FIXED_REGISTERS and also any @@ -173,10 +184,16 @@ extern int target_flags; like. */ #define CALL_USED_REGISTERS \ - { 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0} + { 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 \ + , 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ + , 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 \ + } #define REG_ALLOC_ORDER \ - { 0, 1, 4, 5, 2, 3, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 8, 9} + { 0, 1, 4, 5, 2, 3, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 8, 9 \ + , 42, 43, 44, 45, 46, 47, 48, 49, 34, 35, 36, 37, 38, 39, 40, 41 \ + , 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33 \ + } #define CONDITIONAL_REGISTER_USAGE \ { \ @@ -188,6 +205,13 @@ extern int target_flags; i <= LAST_EXTENDED_REGNUM; i++) \ fixed_regs[i] = call_used_regs[i] = 1; \ } \ + if (!TARGET_AM33_2) \ + { \ + for (i = FIRST_FP_REGNUM; \ + i <= LAST_FP_REGNUM; \ + i++) \ + fixed_regs[i] = call_used_regs[i] = 1; \ + } \ } /* Return number of consecutive hard regs needed starting at reg REGNO @@ -247,6 +271,7 @@ enum reg_class { DATA_OR_ADDRESS_REGS, SP_OR_ADDRESS_REGS, EXTENDED_REGS, DATA_OR_EXTENDED_REGS, ADDRESS_OR_EXTENDED_REGS, SP_OR_EXTENDED_REGS, SP_OR_ADDRESS_OR_EXTENDED_REGS, + FP_REGS, FP_ACC_REGS, GENERAL_REGS, ALL_REGS, LIM_REG_CLASSES }; @@ -260,6 +285,7 @@ enum reg_class { "EXTENDED_REGS", \ "DATA_OR_EXTENDED_REGS", "ADDRESS_OR_EXTENDED_REGS", \ "SP_OR_EXTENDED_REGS", "SP_OR_ADDRESS_OR_EXTENDED_REGS", \ + "FP_REGS", "FP_ACC_REGS", \ "GENERAL_REGS", "ALL_REGS", "LIM_REGS" } /* Define which registers fit in which classes. @@ -267,19 +293,21 @@ enum reg_class { of length N_REG_CLASSES. */ #define REG_CLASS_CONTENTS \ -{ {0}, /* No regs */ \ - {0x0000f}, /* DATA_REGS */ \ - {0x001f0}, /* ADDRESS_REGS */ \ - {0x00200}, /* SP_REGS */ \ - {0x001ff}, /* DATA_OR_ADDRESS_REGS */\ - {0x003f0}, /* SP_OR_ADDRESS_REGS */\ - {0x3fc00}, /* EXTENDED_REGS */ \ - {0x3fc0f}, /* DATA_OR_EXTENDED_REGS */ \ - {0x3fdf0}, /* ADDRESS_OR_EXTENDED_REGS */ \ - {0x3fe00}, /* SP_OR_EXTENDED_REGS */ \ - {0x3fff0}, /* SP_OR_ADDRESS_OR_EXTENDED_REGS */ \ - {0x3fdff}, /* GENERAL_REGS */ \ - {0x3ffff}, /* ALL_REGS */ \ +{ { 0, 0 }, /* No regs */ \ + { 0x0000f, 0 }, /* DATA_REGS */ \ + { 0x001f0, 0 }, /* ADDRESS_REGS */ \ + { 0x00200, 0 }, /* SP_REGS */ \ + { 0x001ff, 0 }, /* DATA_OR_ADDRESS_REGS */\ + { 0x003f0, 0 }, /* SP_OR_ADDRESS_REGS */\ + { 0x3fc00, 0 }, /* EXTENDED_REGS */ \ + { 0x3fc0f, 0 }, /* DATA_OR_EXTENDED_REGS */ \ + { 0x3fdf0, 0 }, /* ADDRESS_OR_EXTENDED_REGS */ \ + { 0x3fe00, 0 }, /* SP_OR_EXTENDED_REGS */ \ + { 0x3fff0, 0 }, /* SP_OR_ADDRESS_OR_EXTENDED_REGS */ \ + { 0xfffc0000, 0x3ffff }, /* FP_REGS */ \ + { 0x03fc0000, 0 }, /* FP_ACC_REGS */ \ + { 0x3fdff, 0 }, /* GENERAL_REGS */ \ + { 0xffffffff, 0x3ffff } /* ALL_REGS */ \ } /* The same information, inverted: @@ -292,6 +320,7 @@ enum reg_class { (REGNO) <= LAST_ADDRESS_REGNUM ? ADDRESS_REGS : \ (REGNO) == STACK_POINTER_REGNUM ? SP_REGS : \ (REGNO) <= LAST_EXTENDED_REGNUM ? EXTENDED_REGS : \ + (REGNO) <= LAST_FP_REGNUM ? FP_REGS : \ NO_REGS) /* The class value for index registers, and the one for base regs. */ @@ -306,6 +335,9 @@ enum reg_class { (C) == 'y' ? SP_REGS : \ ! TARGET_AM33 ? NO_REGS : \ (C) == 'x' ? EXTENDED_REGS : \ + ! TARGET_AM33_2 ? NO_REGS : \ + (C) == 'f' ? FP_REGS : \ + (C) == 'A' ? FP_ACC_REGS : \ NO_REGS) /* Macros to check register numbers against specific register classes. */ @@ -350,6 +382,8 @@ enum reg_class { #define REGNO_AM33_P(regno) \ (REGNO_DATA_P ((regno)) || REGNO_ADDRESS_P ((regno)) \ || REGNO_EXTENDED_P ((regno))) +#define REGNO_FP_P(regno) \ + REGNO_IN_RANGE_P ((regno), FIRST_FP_REGNUM, LAST_FP_REGNUM) #define REGNO_OK_FOR_BASE_P(regno) \ (REGNO_SP_P ((regno)) \ @@ -397,6 +431,11 @@ enum reg_class { #define CLASS_MAX_NREGS(CLASS, MODE) \ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) +/* A class that contains registers which the compiler must always + access in a mode that is the same size as the mode in which it + loaded the register. */ +#define CLASS_CANNOT_CHANGE_SIZE FP_REGS + /* The letters I, J, K, L, M, N, O, P in a register constraint string can be used to stand for particular ranges of immediate operands. This macro defines what the ranges are. @@ -669,6 +708,9 @@ struct cum_arg {int nbytes; }; /* Extra constraints. */ +#define OK_FOR_Q(OP) \ + (GET_CODE (OP) == MEM && ! CONSTANT_ADDRESS_P (XEXP (OP, 0))) + #define OK_FOR_R(OP) \ (GET_CODE (OP) == MEM \ && GET_MODE (OP) == QImode \ @@ -692,6 +734,7 @@ struct cum_arg {int nbytes; }; #define EXTRA_CONSTRAINT(OP, C) \ ((C) == 'R' ? OK_FOR_R (OP) \ + : (C) == 'Q' ? OK_FOR_Q (OP) \ : (C) == 'S' ? GET_CODE (OP) == SYMBOL_REF \ : (C) == 'T' ? OK_FOR_T (OP) \ : 0) @@ -814,6 +857,7 @@ struct cum_arg {int nbytes; }; ! TARGET_AM33 ? 6 : \ (CLASS1 == SP_REGS || CLASS2 == SP_REGS) ? 6 : \ (CLASS1 == CLASS2 && CLASS1 == EXTENDED_REGS) ? 6 : \ + (CLASS1 == FP_REGS || CLASS2 == FP_REGS) ? 6 : \ (CLASS1 == EXTENDED_REGS || CLASS2 == EXTENDED_REGS) ? 4 : \ 4) @@ -885,6 +929,10 @@ struct cum_arg {int nbytes; }; #define REGISTER_NAMES \ { "d0", "d1", "d2", "d3", "a0", "a1", "a2", "a3", "ap", "sp", \ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" \ +, "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7" \ +, "fs8", "fs9", "fs10", "fs11", "fs12", "fs13", "fs14", "fs15" \ +, "fs16", "fs17", "fs18", "fs19", "fs20", "fs21", "fs22", "fs23" \ +, "fs24", "fs25", "fs26", "fs27", "fs28", "fs29", "fs30", "fs31" \ } #define ADDITIONAL_REGISTER_NAMES \ @@ -892,6 +940,10 @@ struct cum_arg {int nbytes; }; {"r12", 0}, {"r13", 1}, {"r14", 2}, {"r15", 3}, \ {"e0", 10}, {"e1", 11}, {"e2", 12}, {"e3", 13}, \ {"e4", 14}, {"e5", 15}, {"e6", 16}, {"e7", 17} \ +, {"fd0", 18}, {"fd2", 20}, {"fd4", 22}, {"fd6", 24} \ +, {"fd8", 26}, {"fd10", 28}, {"fd12", 30}, {"fd14", 32} \ +, {"fd16", 34}, {"fd18", 36}, {"fd20", 38}, {"fd22", 40} \ +, {"fd24", 42}, {"fd26", 44}, {"fd28", 46}, {"fd30", 48} \ } /* Print an instruction operand X on file FILE. @@ -994,3 +1046,15 @@ struct cum_arg {int nbytes; }; #define FILE_ASM_OP "\t.file\n" +#define PREDICATE_CODES \ + {"const_1f_operand", {CONST_INT, CONST_DOUBLE}}, + +typedef struct mn10300_cc_status_mdep + { + int fpCC; + } +cc_status_mdep; + +#define CC_STATUS_MDEP cc_status_mdep + +#define CC_STATUS_MDEP_INIT (cc_status.mdep.fpCC = 0) diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md index f889aa61cdd..a615f6b97ea 100644 --- a/gcc/config/mn10300/mn10300.md +++ b/gcc/config/mn10300/mn10300.md @@ -57,8 +57,8 @@ }") (define_insn "" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d*x*a,d*x,d*x*a,d*x*a,m") - (match_operand:QI 1 "general_operand" "0,I,d*xai,m,d*xa"))] + [(set (match_operand:QI 0 "nonimmediate_operand" "=d*x*a*f,d*x,d*x*a,d*x*a,m,*f,d*x*a") + (match_operand:QI 1 "general_operand" "0,I,d*xai,m,d*xa,d*xa*f,*f"))] "TARGET_AM33 && (register_operand (operands[0], QImode) || register_operand (operands[1], QImode))" @@ -93,11 +93,14 @@ case 3: case 4: return \"movbu %1,%0\"; + case 5: + case 6: + return \"fmov %1,%0\"; default: abort (); } }" - [(set_attr "cc" "none,clobber,none_0hit,none_0hit,none_0hit")]) + [(set_attr "cc" "none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")]) (define_insn "" [(set (match_operand:QI 0 "nonimmediate_operand" "=d*a,d,d*a,d,m") @@ -147,8 +150,8 @@ }") (define_insn "" - [(set (match_operand:HI 0 "nonimmediate_operand" "=d*x*a,d*x,d*x*a,d*x*a,m") - (match_operand:HI 1 "general_operand" "0,I,d*x*ai,m,d*x*a"))] + [(set (match_operand:HI 0 "nonimmediate_operand" "=d*x*a*f,d*x,d*x*a,d*x*a,m,*f,d*x*a") + (match_operand:HI 1 "general_operand" "0,I,d*x*ai,m,d*x*a,d*x*a*f,*f"))] "TARGET_AM33 && (register_operand (operands[0], HImode) || register_operand (operands[1], HImode))" @@ -183,11 +186,14 @@ case 3: case 4: return \"movhu %1,%0\"; + case 5: + case 6: + return \"fmov %1,%0\"; default: abort (); } }" - [(set_attr "cc" "none,clobber,none_0hit,none_0hit,none_0hit")]) + [(set_attr "cc" "none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")]) (define_insn "" [(set (match_operand:HI 0 "nonimmediate_operand" "=d*a,d,d*a,d,m") @@ -277,9 +283,9 @@ (define_insn "" [(set (match_operand:SI 0 "nonimmediate_operand" - "=dx,ax,dx,a,dxm,dxm,axm,axm,dx,dx,ax,ax,axR,!*y") + "=dx,ax,dx,a,dxm,dxm,axm,axm,dx,dx,ax,ax,axR,!*y,*f,*f,dxaQ") (match_operand:SI 1 "general_operand" - "0,0,I,I,dx,ax,dx,ax,dixm,aixm,dixm,aixm,!*y,axR"))] + "0,0,I,I,dx,ax,dx,ax,dixm,aixm,dixm,aixm,!*y,axR,0,dxaQi*f,*f"))] "register_operand (operands[0], SImode) || register_operand (operands[1], SImode)" "* @@ -321,11 +327,16 @@ return \"movu %1,%0\"; } return \"mov %1,%0\"; + case 14: + return \"nop\"; + case 15: + case 16: + return \"fmov %1,%0\"; default: abort (); } }" - [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")]) + [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none,none_0hit,none_0hit")]) (define_expand "movsf" [(set (match_operand:SF 0 "general_operand" "") @@ -340,8 +351,8 @@ }") (define_insn "" - [(set (match_operand:SF 0 "nonimmediate_operand" "=dx,ax,dx,a,daxm,dax") - (match_operand:SF 1 "general_operand" "0,0,G,G,dax,daxFm"))] + [(set (match_operand:SF 0 "nonimmediate_operand" "=f,dx,ax,dx,a,f,dxaQ,daxm,dax") + (match_operand:SF 1 "general_operand" "0,0,0,G,G,fdxaQF,f,dax,daxFm"))] "register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode)" "* @@ -350,12 +361,17 @@ { case 0: case 1: - return \"nop\"; case 2: - return \"clr %0\"; + return \"nop\"; case 3: - case 4: + return \"clr %0\"; + /* case 4: below */ case 5: + case 6: + return \"fmov %1, %0\"; + case 4: + case 7: + case 8: if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS && GET_CODE (operands[1]) == CONST_INT) { @@ -370,7 +386,7 @@ abort (); } }" - [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit")]) + [(set_attr "cc" "none,none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")]) (define_expand "movdi" [(set (match_operand:DI 0 "general_operand" "") @@ -386,9 +402,9 @@ (define_insn "" [(set (match_operand:DI 0 "nonimmediate_operand" - "=dx,ax,dx,a,dxm,dxm,axm,axm,dx,dx,ax,ax") + "=dx,ax,dx,a,dxm,dxm,axm,axm,dx,dx,ax,ax,*f,*f,*f,dxa,*f,Q") (match_operand:DI 1 "general_operand" - "0,0,I,I,dx,ax,dx,ax,dxim,axim,dxim,axim"))] + "0,0,I,I,dx,ax,dx,ax,dxim,axim,dxim,axim,0,*f,dxai,*f,Q,*f"))] "register_operand (operands[0], DImode) || register_operand (operands[1], DImode)" "* @@ -516,6 +532,26 @@ output_asm_insn (\"mov %H1,%H0\", operands); return \"\"; } + case 12: + return \"nop\"; + case 13: + case 14: + case 15: + return \"fmov %L1, %L0\;fmov %H1, %H0\"; + case 16: + if (GET_CODE (operands[1]) == MEM + && GET_CODE (XEXP (operands[1], 0)) == CONST_INT + && (INTVAL (XEXP (operands[1], 0)) & 7) == 0) + return \"fmov %D1, %D0\"; + else + return \"fmov %L1, %L0\;fmov %H1, %H0\"; + case 17: + if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == CONST_INT + && (INTVAL (XEXP (operands[0], 0)) & 7) == 0) + return \"fmov %D1, %D0\"; + else + return \"fmov %L1, %L0\;fmov %H1, %H0\"; default: abort (); } @@ -523,8 +559,9 @@ [(set (attr "cc") (cond [ - (lt (symbol_ref "which_alternative") (const_int 2) - ) (const_string "none") + (ior (lt (symbol_ref "which_alternative") (const_int 2)) + (eq (symbol_ref "which_alternative") (const_int 12)) + ) (const_string "none") (eq (symbol_ref "which_alternative") (const_int 2) ) (const_string "clobber") (eq (symbol_ref "which_alternative") (const_int 3) @@ -555,9 +592,9 @@ (define_insn "" [(set (match_operand:DF 0 "nonimmediate_operand" - "=dx,ax,dx,a,dxm,dxm,axm,axm,dx,dx,ax,ax") + "=f,dx,ax,dx,f,f,dxa,f,Q,a,dxm,dxm,axm,axm,dx,dx,ax,ax") (match_operand:DF 1 "general_operand" - "0,0,G,G,dx,ax,dx,ax,dxFm,axFm,dxFm,axFm"))] + "0,0,0,G,f,dxaF,f,Q,f,G,dx,ax,dx,ax,dxFm,axFm,dxFm,axFm"))] "register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode)" "* @@ -569,24 +606,46 @@ { case 0: case 1: + case 2: return \"nop\"; - case 2: + case 3: return \"clr %L0\;clr %H0\"; - case 3: - if (rtx_equal_p (operands[0], operands[1])) - return \"sub %L1,%L0\;mov %L0,%H0\"; - else - return \"mov %1,%L0\;mov %L0,%H0\"; case 4: case 5: case 6: + return \"fmov %L1, %L0\;fmov %H1, %H0\"; + case 7: + if (GET_CODE (operands[1]) == MEM + && GET_CODE (XEXP (operands[1], 0)) == CONST_INT + && (INTVAL (XEXP (operands[1], 0)) & 7) == 0) + return \"fmov %D1, %D0\"; + else + return \"fmov %L1, %L0\;fmov %H1, %H0\"; + case 8: + if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == CONST_INT + && (INTVAL (XEXP (operands[0], 0)) & 7) == 0) + return \"fmov %D1, %D0\"; + else + return \"fmov %L1, %L0\;fmov %H1, %H0\"; + case 9: + if (rtx_equal_p (operands[0], operands[1])) + return \"sub %L1,%L0\;mov %L0,%H0\"; + else + return \"mov %1,%L0\;mov %L0,%H0\"; case 10: case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: if (GET_CODE (operands[1]) == CONST_INT) { rtx low, high; @@ -692,17 +751,17 @@ [(set (attr "cc") (cond [ - (lt (symbol_ref "which_alternative") (const_int 2) + (lt (symbol_ref "which_alternative") (const_int 3) ) (const_string "none") - (eq (symbol_ref "which_alternative") (const_int 2) - ) (const_string "clobber") (eq (symbol_ref "which_alternative") (const_int 3) + ) (const_string "clobber") + (eq (symbol_ref "which_alternative") (const_int 9) ) (if_then_else (ne (symbol_ref "rtx_equal_p (operands[0], operands[1])") (const_int 0)) (const_string "clobber") (const_string "none_0hit")) - (ior (eq (symbol_ref "which_alternative") (const_int 8)) - (eq (symbol_ref "which_alternative") (const_int 9)) + (ior (eq (symbol_ref "which_alternative") (const_int 14)) + (eq (symbol_ref "which_alternative") (const_int 15)) ) (if_then_else (ne (symbol_ref "mn10300_wide_const_load_uses_clr (operands)") @@ -773,6 +832,14 @@ btst 0,d0 cmp %1,%0" [(set_attr "cc" "compare,compare")]) + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "register_operand" "f,f") + (match_operand:SF 1 "nonmemory_operand" "f,F")))] + "TARGET_AM33_2" + "fcmp %1,%0" + [(set_attr "cc" "compare,compare")]) ;; ---------------------------------------------------------------------- ;; ADD INSTRUCTIONS @@ -1551,6 +1618,8 @@ "" "* { + if (cc_status.mdep.fpCC) + return \"fb%b1 %0\"; if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0 && (GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == GE @@ -1570,6 +1639,8 @@ "" "* { + if (cc_status.mdep.fpCC) + return \"fb%B1 %0\"; if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0 && (GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == GE @@ -1996,6 +2067,12 @@ rtx result; rtx target; + if (TARGET_AM33_2) + { + emit_insn (gen_abssf2_am33_2 (operands[0], operands[1])); + DONE; + } + target = operand_subword_force (operands[0], 0, SFmode); result = expand_binop (SImode, and_optab, operand_subword_force (operands[1], 0, SFmode), @@ -2012,6 +2089,15 @@ }") +(define_insn "abssf2_am33_2" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (abs:SF (match_operand:SF 1 "register_operand" "0,?f")))] + "TARGET_AM33_2" + "@ + fabs %0 + fabs %1, %0" + [(set_attr "cc" "none_0hit")]) + (define_expand "negdf2" [(set (match_operand:DF 0 "register_operand" "") (neg:DF (match_operand:DF 1 "register_operand" "")))] @@ -2052,6 +2138,12 @@ rtx result; rtx target; + if (TARGET_AM33_2) + { + emit_insn (gen_negsf2_am33_2 (operands[0], operands[1])); + DONE; + } + target = operand_subword_force (operands[0], 0, SFmode); result = expand_binop (SImode, xor_optab, operand_subword_force (operands[1], 0, SFmode), @@ -2068,6 +2160,114 @@ DONE; }") +(define_insn "negsf2_am33_2" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (neg:SF (match_operand:SF 1 "register_operand" "0,?f")))] + "TARGET_AM33_2" + "@ + fneg %0 + fneg %1, %0" + [(set_attr "cc" "none_0hit")]) + +(define_expand "sqrtsf2" + [(set (match_operand:SF 0 "register_operand" "") + (sqrt:SF (match_operand:SF 1 "register_operand" "")))] + "TARGET_AM33_2 && flag_unsafe_math_optimizations" + " +{ + rtx scratch = gen_reg_rtx (SFmode); + emit_insn (gen_rsqrtsf2 (scratch, operands[1], CONST1_RTX (SFmode))); + emit_insn (gen_divsf3 (operands[0], force_reg (SFmode, CONST1_RTX (SFmode)), + scratch)); + DONE; +}") + +(define_insn "rsqrtsf2" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (div:SF (match_operand:SF 2 "const_1f_operand" "F,F") + (sqrt:SF (match_operand:SF 1 "register_operand" "0,?f"))))] + "TARGET_AM33_2" + "@ + frsqrt %0 + frsqrt %1, %0" + [(set_attr "cc" "none_0hit")]) + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (plus:SF (match_operand:SF 1 "register_operand" "%0,f") + (match_operand:SF 2 "general_operand" "f,?fF")))] + "TARGET_AM33_2" + "@ + fadd %2, %0 + fadd %2, %1, %0" + [(set_attr "cc" "none_0hit")]) + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (minus:SF (match_operand:SF 1 "register_operand" "0,f") + (match_operand:SF 2 "general_operand" "f,?fF")))] + "TARGET_AM33_2" + "@ + fsub %2, %0 + fsub %2, %1, %0" + [(set_attr "cc" "none_0hit")]) + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (mult:SF (match_operand:SF 1 "register_operand" "%0,f") + (match_operand:SF 2 "general_operand" "f,?fF")))] + "TARGET_AM33_2" + "@ + fmul %2, %0 + fmul %2, %1, %0" + [(set_attr "cc" "none_0hit")]) + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (div:SF (match_operand:SF 1 "register_operand" "0,f") + (match_operand:SF 2 "general_operand" "f,?fF")))] + "TARGET_AM33_2" + "@ + fdiv %2, %0 + fdiv %2, %1, %0" + [(set_attr "cc" "none_0hit")]) + +(define_insn "fmaddsf4" + [(set (match_operand:SF 0 "register_operand" "=A") + (plus:SF (mult:SF (match_operand:SF 1 "register_operand" "%f") + (match_operand:SF 2 "register_operand" "f")) + (match_operand:SF 3 "register_operand" "f")))] + "TARGET_AM33_2" + "fmadd %1, %2, %3, %0" + [(set_attr "cc" "none_0hit")]) + +(define_insn "fmsubsf4" + [(set (match_operand:SF 0 "register_operand" "=A") + (minus:SF (mult:SF (match_operand:SF 1 "register_operand" "%f") + (match_operand:SF 2 "register_operand" "f")) + (match_operand:SF 3 "register_operand" "f")))] + "TARGET_AM33_2" + "fmsub %1, %2, %3, %0" + [(set_attr "cc" "none_0hit")]) + +(define_insn "fnmaddsf4" + [(set (match_operand:SF 0 "register_operand" "=A") + (minus:SF (match_operand:SF 3 "register_operand" "f") + (mult:SF (match_operand:SF 1 "register_operand" "%f") + (match_operand:SF 2 "register_operand" "f"))))] + "TARGET_AM33_2" + "fnmadd %1, %2, %3, %0" + [(set_attr "cc" "none_0hit")]) + +(define_insn "fnmsubsf4" + [(set (match_operand:SF 0 "register_operand" "=A") + (minus:SF (neg:SF (mult:SF (match_operand:SF 1 "register_operand" "%f") + (match_operand:SF 2 "register_operand" "f"))) + (match_operand:SF 3 "register_operand" "f")))] + "TARGET_AM33_2" + "fnmsub %1, %2, %3, %0" + [(set_attr "cc" "none_0hit")]) + ;; ---------------------------------------------------------------------- ;; PROLOGUE/EPILOGUE diff --git a/gcc/config/mn10300/t-mn10300 b/gcc/config/mn10300/t-mn10300 index 2e26e229acc..a35b2c50185 100644 --- a/gcc/config/mn10300/t-mn10300 +++ b/gcc/config/mn10300/t-mn10300 @@ -10,8 +10,8 @@ fp-bit.c: $(srcdir)/config/fp-bit.c echo '#define FLOAT' > fp-bit.c cat $(srcdir)/config/fp-bit.c >> fp-bit.c -MULTILIB_OPTIONS = mam33 -MULTILIB_DIRNAMES = am33 +MULTILIB_OPTIONS = mam33/mam33-2 +MULTILIB_DIRNAMES = am33 am33-2 LIBGCC = stmp-multilib INSTALL_LIBGCC = install-multilib diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 79f57af8a7b..bd491347203 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -386,6 +386,7 @@ in the following sections. @emph{MN10300 Options} @gccoptlist{-mmult-bug -mno-mult-bug @gol -mam33 -mno-am33 @gol +-mam33-2 -mno-am33-2 @gol -mno-crt0 -mrelax} @emph{M32R/D Options} -- 2.11.4.GIT