This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

AM33/2.0 support in mn10300-elf


This patch adds support for AM33/2.0 to the mn10300-elf port.
AM33/2.0 introduces a single-precision floating point unit to the
original AM33.  It's a shame that it took me so long to contribute
this port, it was the first one I worked on at Red Hat.  Anyway, here
it is.  Enjoy!  I'm checking this in.  Tested with a cross from
i686-pc-linux-gnu.  Binutils has just went in; GDB and newlib bits to
be posted momentarily.

Index: gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* 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.

Index: gcc/config/mn10300/mn10300.c
===================================================================
RCS file: /cvs/uberbaum/gcc/config/mn10300/mn10300.c,v
retrieving revision 1.52
diff -u -p -r1.52 mn10300.c
--- gcc/config/mn10300/mn10300.c 3 Jul 2003 12:34:09 -0000 1.52
+++ gcc/config/mn10300/mn10300.c 9 Jul 2003 22:56:29 -0000
@@ -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:
Index: gcc/config/mn10300/mn10300.h
===================================================================
RCS file: /cvs/uberbaum/gcc/config/mn10300/mn10300.h,v
retrieving revision 1.71
diff -u -p -r1.71 mn10300.h
--- gcc/config/mn10300/mn10300.h 19 Jun 2003 21:47:18 -0000 1.71
+++ gcc/config/mn10300/mn10300.h 9 Jul 2003 22:56:30 -0000
@@ -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)
Index: gcc/config/mn10300/mn10300.md
===================================================================
RCS file: /cvs/uberbaum/gcc/config/mn10300/mn10300.md,v
retrieving revision 1.45
diff -u -p -r1.45 mn10300.md
--- gcc/config/mn10300/mn10300.md 14 Feb 2003 21:47:48 -0000 1.45
+++ gcc/config/mn10300/mn10300.md 9 Jul 2003 22:56:30 -0000
@@ -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),
@@ -2067,6 +2159,114 @@
   emit_move_insn (operands[0], operands[0]);
   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")])
 
 
 ;; ----------------------------------------------------------------------
Index: gcc/config/mn10300/t-mn10300
===================================================================
RCS file: /cvs/uberbaum/gcc/config/mn10300/t-mn10300,v
retrieving revision 1.8
diff -u -p -r1.8 t-mn10300
--- gcc/config/mn10300/t-mn10300 17 May 2001 03:16:07 -0000 1.8
+++ gcc/config/mn10300/t-mn10300 9 Jul 2003 22:56:30 -0000
@@ -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
Index: gcc/doc/invoke.texi
===================================================================
RCS file: /cvs/uberbaum/gcc/doc/invoke.texi,v
retrieving revision 1.314
diff -u -p -r1.314 invoke.texi
--- gcc/doc/invoke.texi 9 Jul 2003 04:07:44 -0000 1.314
+++ gcc/doc/invoke.texi 9 Jul 2003 22:56:49 -0000
@@ -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}
-- 
Alexandre Oliva   Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer                 aoliva@{redhat.com, gcc.gnu.org}
CS PhD student at IC-Unicamp        oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist                Professional serial bug killer

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]