diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 724738e1f77bd5cd78604a0aa910a4b7eb490414..79def92e588575db2bfa54db6b8e445ad14440c4 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,20 @@
+Thu Dec 12 16:24:59 2002  J"orn Rennecke <joern.rennecke@superh.com>
+
+	* sh.c (reg_class_from_letter): No longer const.  Add 'e' entry.
+	(sh_register_move_cost): Add clause for SImode fp-fp moves.
+	Increase cost for moves involving multiple general purpose registers.
+	* sh.h (OVERRIDE_OPTIONS): Set reg_class_from_letter['e'] according to
+	TARGET_FMOVD.
+	(HARD_REGNO_MODE_OK): Allow V2SFmode and V4SFmode in general purpose
+	registers, and SImode in fp registers, for ! TARGET_SHMEDIA.
+	(enum reg_class reg_class_from_letter): No longer const.
+	(SECONDARY_OUTPUT_RELOAD_CLASS): Use REGCLASS_HAS_FP_REG /
+	REGCLASS_HAS_GENERAL_REG.
+	Handle SImode moves from/to fp registers.
+	! TARGET_SHMEDIA && TARGET_FMOVD.
+	(SECONDARY_INPUT_RELOAD_CLASS): Use REGCLASS_HAS_FP_REG.
+	* sh.md (movsi_ie): Add alternatives to move from / to fp regisyters.
+
 2002-12-12  Andreas Schwab  <schwab@suse.de>
 
 	* config/ia64/ia64.c (ia64_hpux_asm_file_end): Fix typo in last
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index e77bc11bd17119e5f41a9855a5c7ccf099801ec1..824914c42d2232106525983d504d4a91c4c2312f 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -154,16 +154,17 @@ char sh_additional_register_names[ADDREGNAMES_SIZE] \
   = SH_ADDITIONAL_REGISTER_NAMES_INITIALIZER;
 
 /* Provide reg_class from a letter such as appears in the machine
-   description.  */
+   description.  *: target independently reserved letter.
+   reg_class_from_letter['e'] is set to NO_REGS for TARGET_FMOVD.  */
 
-const enum reg_class reg_class_from_letter[] =
+enum reg_class reg_class_from_letter[] =
 {
-  /* a */ ALL_REGS, /* b */ TARGET_REGS, /* c */ FPSCR_REGS, /* d */ DF_REGS,
-  /* e */ NO_REGS, /* f */ FP_REGS, /* g */ NO_REGS, /* h */ NO_REGS,
-  /* i */ NO_REGS, /* j */ NO_REGS, /* k */ SIBCALL_REGS, /* l */ PR_REGS,
-  /* m */ NO_REGS, /* n */ NO_REGS, /* o */ NO_REGS, /* p */ NO_REGS,
-  /* q */ NO_REGS, /* r */ NO_REGS, /* s */ NO_REGS, /* t */ T_REGS,
-  /* u */ NO_REGS, /* v */ NO_REGS, /* w */ FP0_REGS, /* x */ MAC_REGS,
+  /* a */ ALL_REGS,  /* b */ TARGET_REGS, /* c */ FPSCR_REGS, /* d */ DF_REGS,
+  /* e */ FP_REGS,   /* f */ FP_REGS,  /* g **/ NO_REGS,     /* h */ NO_REGS,
+  /* i **/ NO_REGS,  /* j */ NO_REGS,  /* k */ SIBCALL_REGS, /* l */ PR_REGS,
+  /* m **/ NO_REGS,  /* n **/ NO_REGS, /* o **/ NO_REGS,     /* p **/ NO_REGS,
+  /* q */ NO_REGS,   /* r **/ NO_REGS, /* s **/ NO_REGS,     /* t */ T_REGS,
+  /* u */ NO_REGS,   /* v */ NO_REGS,  /* w */ FP0_REGS,     /* x */ MAC_REGS,
   /* y */ FPUL_REGS, /* z */ R0_REGS
 };
 
@@ -7784,9 +7785,8 @@ sh_mark_label (address, nuses)
 /* Compute extra cost of moving data between one register class
    and another.  */
 
-/* Regclass always uses 2 for moves in the same register class;
-   If SECONDARY*_RELOAD_CLASS says something about the src/dst pair,
-   it uses this information.  Hence, the general register <-> floating point
+/* If SECONDARY*_RELOAD_CLASS says something about the src/dst pair, regclass
+   uses this information.  Hence, the general register <-> floating point
    register information here is not used for SFmode.  */
 
 int
@@ -7797,6 +7797,11 @@ sh_register_move_cost (mode, srcclass, dstclass)
   if (dstclass == T_REGS || dstclass == PR_REGS)
     return 10;
 
+  if (mode == SImode && ! TARGET_SHMEDIA && TARGET_FMOVD
+      && REGCLASS_HAS_FP_REG (srcclass)
+      && REGCLASS_HAS_FP_REG (dstclass))
+    return 4;
+
   if ((REGCLASS_HAS_FP_REG (dstclass)
        && REGCLASS_HAS_GENERAL_REG (srcclass))
       || (REGCLASS_HAS_GENERAL_REG (dstclass)
@@ -7824,7 +7829,13 @@ sh_register_move_cost (mode, srcclass, dstclass)
       || (dstclass == FPSCR_REGS && ! REGCLASS_HAS_GENERAL_REG (srcclass)))
   return 4;
 
-  return 2 * ((GET_MODE_SIZE (mode) + 7) / 8U);
+  if (TARGET_SHMEDIA
+      || (TARGET_FMOVD
+	  && ! REGCLASS_HAS_GENERAL_REG (srcclass)
+	  && ! REGCLASS_HAS_GENERAL_REG (dstclass)))
+    return 2 * ((GET_MODE_SIZE (mode) + 7) / 8U);
+
+  return 2 * ((GET_MODE_SIZE (mode) + 3) / 4U);
 }
 
 #include "gt-sh.h"
diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h
index 0d0869099af9e4421ea44944c5b2f76f493c20bf..f84e6fb8956f13ed4949ac143c7d082b75bd9aa9 100644
--- a/gcc/config/sh/sh.h
+++ b/gcc/config/sh/sh.h
@@ -444,6 +444,8 @@ do {									\
        targetm.asm_out.aligned_op.di = NULL;				\
        targetm.asm_out.unaligned_op.di = NULL;				\
     }									\
+  if (TARGET_FMOVD)							\
+    reg_class_from_letter['e'] = NO_REGS;				\
 									\
   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)		\
     if (! VALID_REGISTER_P (regno))					\
@@ -912,16 +914,16 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \
    ? 1 \
    : (MODE) == V2SFmode \
    ? ((FP_REGISTER_P (REGNO) && ((REGNO) - FIRST_FP_REG) % 2 == 0) \
-      || (TARGET_SHMEDIA && GENERAL_REGISTER_P (REGNO))) \
+      || GENERAL_REGISTER_P (REGNO)) \
    : (MODE) == V4SFmode \
-   ? (FP_REGISTER_P (REGNO) && ((REGNO) - FIRST_FP_REG) % 4 == 0) \
+   ? ((FP_REGISTER_P (REGNO) && ((REGNO) - FIRST_FP_REG) % 4 == 0) \
+      || (! TARGET_SHMEDIA && GENERAL_REGISTER_P (REGNO))) \
    : (MODE) == V16SFmode \
    ? (TARGET_SHMEDIA \
       ? (FP_REGISTER_P (REGNO) && ((REGNO) - FIRST_FP_REG) % 16 == 0) \
       : (REGNO) == FIRST_XD_REG) \
    : FP_REGISTER_P (REGNO) \
-   ? ((MODE) == SFmode \
-      || (TARGET_SHMEDIA && (MODE) == SImode) \
+   ? ((MODE) == SFmode || (MODE) == SImode \
       || ((TARGET_SH3E || TARGET_SHMEDIA) && (MODE) == SCmode) \
       || (((TARGET_SH4 && (MODE) == DFmode) || (MODE) == DCmode \
 	   || (TARGET_SHMEDIA && ((MODE) == DFmode || (MODE) == DImode \
@@ -1237,7 +1239,7 @@ extern int regno_reg_class[FIRST_PSEUDO_REGISTER];
 
 /* Get reg_class from a letter such as appears in the machine
    description.  */
-extern const enum reg_class reg_class_from_letter[];
+extern enum reg_class reg_class_from_letter[];
 
 #define REG_CLASS_FROM_LETTER(C) \
    ( ISLOWER (C) ? reg_class_from_letter[(C)-'a'] : NO_REGS )
@@ -1302,16 +1304,20 @@ extern const enum reg_class reg_class_from_letter[];
    : (CLASS)) \
 
 #define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS,MODE,X) \
-  ((((((CLASS) == FP_REGS || (CLASS) == FP0_REGS			\
-	|| (CLASS) == DF_REGS || (CLASS) == DF_HI_REGS)			\
-      && (GET_CODE (X) == REG && GENERAL_OR_AP_REGISTER_P (REGNO (X))))	\
-     || (((CLASS) == GENERAL_REGS || (CLASS) == R0_REGS)		\
+  ((((REGCLASS_HAS_FP_REG (CLASS) 					\
+      && (GET_CODE (X) == REG						\
+      && (GENERAL_OR_AP_REGISTER_P (REGNO (X))				\
+	  || (FP_REGISTER_P (REGNO (X)) && (MODE) == SImode		\
+	      && TARGET_FMOVD))))					\
+     || (REGCLASS_HAS_GENERAL_REG (CLASS) 				\
 	 && GET_CODE (X) == REG						\
 	 && FP_REGISTER_P (REGNO (X))))					\
     && ! TARGET_SHMEDIA							\
-    && MODE == SFmode)							\
+    && ((MODE) == SFmode || (MODE) == SImode))				\
    ? FPUL_REGS								\
-   : ((CLASS) == FPUL_REGS						\
+   : (((CLASS) == FPUL_REGS						\
+       || (REGCLASS_HAS_FP_REG (CLASS)					\
+	   && ! TARGET_SHMEDIA && MODE == SImode))			\
       && (GET_CODE (X) == MEM						\
 	  || (GET_CODE (X) == REG					\
 	      && (REGNO (X) >= FIRST_PSEUDO_REGISTER			\
@@ -1332,8 +1338,7 @@ extern const enum reg_class reg_class_from_letter[];
    ? GENERAL_REGS : NO_REGS)
 
 #define SECONDARY_INPUT_RELOAD_CLASS(CLASS,MODE,X)  \
-  ((((CLASS) == FP_REGS || (CLASS) == FP0_REGS || (CLASS) == DF_REGS	\
-     || (CLASS) == DF_HI_REGS)						\
+  ((REGCLASS_HAS_FP_REG (CLASS) 					\
     && ! TARGET_SHMEDIA							\
     && immediate_operand ((X), (MODE))					\
     && ! ((fp_zero_operand (X) || fp_one_operand (X))			\
@@ -1352,7 +1357,7 @@ extern const enum reg_class reg_class_from_letter[];
       && ((GET_CODE (X) == REG && REGNO (X) >= FIRST_PSEUDO_REGISTER)	\
 	  || (GET_CODE (X) == MEM && GET_CODE (XEXP ((X), 0)) == PLUS)))\
    ? GENERAL_REGS							\
-   : (((CLASS) == FP_REGS || (CLASS) == DF_REGS || (CLASS) == DF_HI_REGS)\
+   : (REGCLASS_HAS_FP_REG (CLASS) 					\
       && TARGET_SHMEDIA							\
       && immediate_operand ((X), (MODE))				\
       && (X) != CONST0_RTX (GET_MODE (X))				\
@@ -2807,15 +2812,13 @@ while (0)
 /* Compute extra cost of moving data between one register class
    and another.  */
 
-/* Regclass always uses 2 for moves in the same register class;
-   If SECONDARY*_RELOAD_CLASS says something about the src/dst pair,
-   it uses this information.  Hence, the general register <-> floating point
+/* If SECONDARY*_RELOAD_CLASS says something about the src/dst pair, regclass
+   uses this information.  Hence, the general register <-> floating point
    register information here is not used for SFmode.  */
 
 #define REGCLASS_HAS_GENERAL_REG(CLASS) \
   ((CLASS) == GENERAL_REGS || (CLASS) == R0_REGS \
     || (! TARGET_SHMEDIA && (CLASS) == SIBCALL_REGS))
-/* NB SIBCALL_REGS are not strictly general, as they include TR0-TR4 */
 
 #define REGCLASS_HAS_FP_REG(CLASS) \
   ((CLASS) == FP0_REGS || (CLASS) == FP_REGS \
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index e545b0a63d2d194a2e42c7d7c343af58d68c80c5..1df69d194958d47dbec803f223efa32827876efa 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -3408,9 +3408,11 @@
 ;; (subreg:SI (reg:SF FR14_REG) 0) into T (compiling stdlib/strtod.c -m3e -O2)
 ;; ??? This allows moves from macl to fpul to be recognized, but these moves
 ;; will require a reload.
+;; ??? We can't include f/f because we need the proper FPSCR setting when
+;; TARGET_FMOVD is in effect, and mode switching is done before reload.
 (define_insn "movsi_ie"
-  [(set (match_operand:SI 0 "general_movdst_operand" "=r,r,t,r,r,r,r,m,<,<,x,l,x,l,y,<,r,y,r,y")
-	(match_operand:SI 1 "general_movsrc_operand" "Q,rI,r,mr,x,l,t,r,x,l,r,r,>,>,>,y,i,r,y,y"))]
+  [(set (match_operand:SI 0 "general_movdst_operand" "=r,r,t,r,r,r,r,m,<,<,x,l,x,l,y,<,r,y,r,*f,y,*f,y")
+	(match_operand:SI 1 "general_movsrc_operand" "Q,rI,r,mr,x,l,t,r,x,l,r,r,>,>,>,y,i,r,y,y,*f,*f,y"))]
   "TARGET_SH3E
    && (register_operand (operands[0], SImode)
        || register_operand (operands[1], SImode))"
@@ -3434,10 +3436,13 @@
 	fake	%1,%0
 	lds	%1,%0
 	sts	%1,%0
+	fsts	fpul,%0
+	flds	%1,fpul
+	fmov	%1,%0
 	! move optimized away"
-  [(set_attr "type" "pcload_si,move,*,load_si,mac_gp,prget,move,store,store,pstore,move,prset,load,pload,load,store,pcload_si,gp_fpul,fpul_gp,nil")
-   (set_attr "late_fp_use" "*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,yes,*,*,yes,*")
-   (set_attr "length" "*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,0")])
+  [(set_attr "type" "pcload_si,move,*,load_si,mac_gp,prget,move,store,store,pstore,move,prset,load,pload,load,store,pcload_si,gp_fpul,fpul_gp,fmove,fmove,fmove,nil")
+   (set_attr "late_fp_use" "*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,yes,*,*,yes,*,*,*,*")
+   (set_attr "length" "*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,0")])
 
 (define_insn "movsi_i_lowpart"
   [(set (strict_low_part (match_operand:SI 0 "general_movdst_operand" "+r,r,r,r,r,r,m,r"))