summaryrefslogtreecommitdiff
path: root/gcc/config/mn10300
diff options
context:
space:
mode:
authoraoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>2003-07-10 02:56:29 +0000
committeraoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>2003-07-10 02:56:29 +0000
commitb166356e0aae66eb9affc05c891d8cf851728186 (patch)
treeecefedbe1603c74086c9d6117c3c3c9692cecd7a /gcc/config/mn10300
parent332a53e3a0c742311624c0861bfc22ac7ef9a7c5 (diff)
downloadgcc-b166356e0aae66eb9affc05c891d8cf851728186.tar.gz
* config/mn10300/mn10300.h (PREDICATE_CODES): Define.
2001-05-01 Alexandre Oliva <aoliva@redhat.com> * config/mn10300/mn10300.md (sqrtsf2): flag_fast_math was renamed to flag_unsafe_math_optimizations. 2001-04-14 Alexandre Oliva <aoliva@redhat.com> * config/mn10300/mn10300.c (expand_prologue): Mark FP-register-saving insns as frame-related. 2001-02-13 Alexandre Oliva <aoliva@redhat.com> * 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 <aoliva@redhat.com> * config/mn10300/mn10300.h (DBX_REGISTER_NUMBER): Added floating-point registers. 2000-08-07 Alexandre Oliva <aoliva@redhat.com> * config/mn10300/mn10300.md (movdf): Revert some am33-specific pessimizations that had gone in on 2000-05-08. 2000-06-28 Graham Stott <grahams@cygnus.co.uk> * config/mn10300/mn10300.h (REG_CLASS_CONTENTS): Fix typo. 2000-06-22 Graham Stott <grahams@cygnus.co.uk> * 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 <aoliva@cygnus.com> * 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 <aoliva@cygnus.com> * config/mn10300/mn10300.md (movdi, movdf): 64-bit clean-up. 2000-05-13 Alexandre Oliva <aoliva@cygnus.com> * config/mn10300/mn10300.md (abssf2, negsf2, rsqrtsf2, addsf3, subsf3, mulsf3, divsf3, fmaddsf4, fmsubsf4, fnmaddsf4, fnmsubsf4): Do not clobber cc0. 2000-05-12 Alexandre Oliva <aoliva@cygnus.com> * 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 <aoliva@cygnus.com> * 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 <aoliva@cygnus.com> * config/mn10300/mn10300.md (movdf): Oops, I missed it in my previous check-in. 2000-05-08 Alexandre Oliva <aoliva@cygnus.com> * 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 <aoliva@cygnus.com> * 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 <aoliva@cygnus.com> * config/mn10300/mn10300.h (REG_CLASS_CONTENTS): Remove FP regs from GENERAL_REGS. 2000-04-27 Alexandre Oliva <aoliva@cygnus.com> * 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 <aoliva@cygnus.com> * config/mn10300/mn10300.h (CLASS_CANNOT_CHANGE_SIZE): Defined as FP_REGS. 2000-04-21 Alexandre Oliva <aoliva@cygnus.com> * 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
Diffstat (limited to 'gcc/config/mn10300')
-rw-r--r--gcc/config/mn10300/mn10300.c547
-rw-r--r--gcc/config/mn10300/mn10300.h102
-rw-r--r--gcc/config/mn10300/mn10300.md264
-rw-r--r--gcc/config/mn10300/t-mn103004
4 files changed, 858 insertions, 59 deletions
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