Index: config/pdp11/pdp11-protos.h
===================================================================
--- config/pdp11/pdp11-protos.h	(revision 165973)
+++ config/pdp11/pdp11-protos.h	(working copy)
@@ -31,7 +31,11 @@
 extern const char *output_block_move (rtx *);
 extern const char *output_jump (enum rtx_code, int, int);
 extern void print_operand_address (FILE *, rtx);
-extern int pdp11_register_move_cost (enum reg_class, enum reg_class);
+extern bool pdp11_cannot_change_mode_class (enum machine_mode,
+                                            enum machine_mode, enum reg_class);
+extern bool pdp11_secondary_memory_needed (reg_class_t, reg_class_t, 
+					   enum machine_mode);
+
 #endif /* RTX_CODE */
 
 extern void output_ascii (FILE *, const char *, int);
Index: config/pdp11/predicates.md
===================================================================
--- config/pdp11/predicates.md	(revision 165973)
+++ config/pdp11/predicates.md	(working copy)
@@ -35,3 +35,12 @@
   sh = INTVAL (op);
   return (abs (sh) > 1 && abs (sh) <= 4);
 })
+
+;; Accept anything general-operand accepts, except that registers must
+;; be FPU registers.
+(define_predicate "float_operand"
+  (if_then_else (match_code "reg")
+		(ior 
+		 (match_test "REGNO_REG_CLASS (REGNO (op)) == LOAD_FPU_REGS")
+		 (match_test "REGNO_REG_CLASS (REGNO (op)) == NO_LOAD_FPU_REGS"))
+		(match_test "general_operand (op, mode)")))
Index: config/pdp11/pdp11.md
===================================================================
--- config/pdp11/pdp11.md	(revision 165973)
+++ config/pdp11/pdp11.md	(working copy)
@@ -25,6 +25,7 @@
 (define_constants
   [
    ;; Register numbers
+   (RETVAL_REGNUM     	  0)
    (FRAME_POINTER_REGNUM  5)
    (STACK_POINTER_REGNUM  6)
    (PC_REGNUM             7)
@@ -196,7 +197,7 @@
 (define_expand "cbranchdf4"
   [(set (cc0)
         (compare (match_operand:DF 1 "general_operand")
-		 (match_operand:DF 2 "general_operand")))
+		 (match_operand:DF 2 "register_or_const0_operand")))
    (set (pc)
 	(if_then_else (match_operator 0 "ordered_comparison_operator"
 		       [(cc0) (const_int 0)])
@@ -318,11 +319,9 @@
 }"
   [(set_attr "length" "2,4,4,6")])
 
-;; do we have to supply all these moves? e.g. to 
-;; NO_LOAD_FPU_REGs ? 
 (define_insn "movdf"
-  [(set (match_operand:DF 0 "general_operand" "=a,fR,a,Q,g")
-        (match_operand:DF 1 "general_operand" "fFR,a,Q,a,g"))]
+  [(set (match_operand:DF 0 "float_operand" "=a,fR,a,Q,g")
+        (match_operand:DF 1 "float_operand" "fFR,a,Q,a,g"))]
   "TARGET_FPU"
   "* if (which_alternative ==0 || which_alternative == 2)
        return \"ldd %1, %0\";
@@ -334,11 +333,17 @@
   [(set_attr "length" "2,2,10,10,32")])
 
 (define_insn "movsf"
-  [(set (match_operand:SF 0 "general_operand" "=g,r,g")
-        (match_operand:SF 1 "general_operand" "r,rmF,g"))]
+  [(set (match_operand:SF 0 "float_operand" "=a,fR,a,Q,g")
+        (match_operand:SF 1 "float_operand" "fFR,a,Q,a,g"))]
   "TARGET_FPU"
-  "* return output_move_double (operands);"
-  [(set_attr "length" "16,16,16")])
+  "* if (which_alternative ==0 || which_alternative == 2)
+       return \"{ldcfd|movof} %1, %0\";
+     else if (which_alternative == 1 || which_alternative == 3)
+       return \"{stcdf|movfo} %1, %0\";
+     else 
+       return output_move_double (operands); "
+;; just a guess..
+  [(set_attr "length" "2,2,10,10,16")])
 
 ;; maybe fiddle a bit with move_ratio, then 
 ;; let constraints only accept a register ...
@@ -386,15 +391,11 @@
 ;;- truncation instructions
 
 (define_insn  "truncdfsf2"
-  [(set (match_operand:SF 0 "general_operand" "=r,R,Q")
-	(float_truncate:SF (match_operand:DF 1 "register_operand" "a,a,a")))]
+  [(set (match_operand:SF 0 "general_operand" "=f,R,Q")
+	(float_truncate:SF (match_operand:DF 1 "register_operand" "f,a,a")))]
   "TARGET_FPU"
   "* if (which_alternative ==0)
      {
-       output_asm_insn(\"{stcdf|movfo} %1, -(sp)\", operands);
-       output_asm_insn(\"mov (sp)+, %0\", operands);
-       operands[0] = gen_rtx_REG (HImode, REGNO (operands[0])+1);
-       output_asm_insn(\"mov (sp)+, %0\", operands);
        return \"\";
      }
      else if (which_alternative == 1)
@@ -402,7 +403,7 @@
      else 
        return \"{stcdf|movfo} %1, %0\";
   "
-  [(set_attr "length" "6,2,4")])
+  [(set_attr "length" "0,2,4")])
 
 
 (define_expand "truncsihi2"
@@ -439,14 +440,14 @@
 ;;- sign extension instructions
 
 (define_insn "extendsfdf2"
-  [(set (match_operand:DF 0 "register_operand" "=a,a,a")
-	(float_extend:DF (match_operand:SF 1 "general_operand" "r,R,Q")))]
+  [(set (match_operand:DF 0 "register_operand" "=f,a,a")
+	(float_extend:DF (match_operand:SF 1 "general_operand" "f,R,Q")))]
   "TARGET_FPU"
   "@
-   mov %1, -(sp)\;{ldcfd|movof} (sp)+,%0
+   /* nothing */
    {ldcfd|movof} %1, %0
    {ldcfd|movof} %1, %0"
-  [(set_attr "length" "4,2,4")])
+  [(set_attr "length" "0,2,4")])
 
 ;; does movb sign extend in register-to-register move?
 (define_insn "extendqihi2"
@@ -856,6 +857,7 @@
 }"
   [(set_attr "length" "4,8,8,12,4,4,8,6,6,12")])
 
+;; FIXME This definition is wrong, PR/41822
 (define_insn "andhi3"
   [(set (match_operand:HI 0 "general_operand" "=rR,rR,Q,Q")
 	(and:HI (match_operand:HI 1 "general_operand" "0,0,0,0")
Index: config/pdp11/pdp11.c
===================================================================
--- config/pdp11/pdp11.c	(revision 165973)
+++ config/pdp11/pdp11.c	(working copy)
@@ -216,7 +216,17 @@
 #undef TARGET_TRAMPOLINE_INIT
 #define TARGET_TRAMPOLINE_INIT pdp11_trampoline_init
 
-struct gcc_target targetm = TARGET_INITIALIZER;
+#undef  TARGET_SECONDARY_RELOAD
+#define TARGET_SECONDARY_RELOAD pdp11_secondary_reload
+
+#undef  TARGET_REGISTER_MOVE_COST 
+#define TARGET_REGISTER_MOVE_COST pdp11_register_move_cost
+
+#undef  TARGET_PREFERRED_RELOAD_CLASS
+#define TARGET_PREFERRED_RELOAD_CLASS pdp11_preferred_reload_class
+
+#undef  TARGET_PREFERRED_OUTPUT_RELOAD_CLASS
+#define TARGET_PREFERRED_OUTPUT_RELOAD_CLASS pdp11_preferred_output_reload_class
 
 /* Implement TARGET_HANDLE_OPTION.  */
 
@@ -417,7 +427,7 @@
 	
 	/* get ACs */
 	for (i = AC5_REGNUM; i >= AC0_REGNUM; i--)
-	  if (df_regs_ever_live_p (i) && call_used_regs[i])
+	  if (df_regs_ever_live_p (i) && ! call_used_regs[i])
 		via_ac = i;
 	
 	for (i = AC5_REGNUM; i >= AC0_REGNUM; i--)
@@ -1054,22 +1064,23 @@
              /* NO  MUL  GEN  LFPU  NLFPU FPU ALL */
 
 /* NO */     {  0,   0,   0,    0,    0,    0,   0},
-/* MUL */    {  0,   2,   2,   10,   22,   22,  22},
-/* GEN */    {  0,   2,   2,   10,   22,   22,  22},
-/* LFPU */   {  0,  10,  10,    2,    2,    2,  10},
-/* NLFPU */  {  0,  22,  22,    2,    2,    2,  22},
-/* FPU */    {  0,  22,  22,    2,    2,    2,  22},
-/* ALL */    {  0,  22,  22,   10,   22,   22,  22}
+/* MUL */    {  0,   2,   2,   22,   22,   22,  22},
+/* GEN */    {  0,   2,   2,   22,   22,   22,  22},
+/* LFPU */   {  0,  22,  22,    2,    2,    2,  22},
+/* NLFPU */  {  0,  22,  22,    2,   10,   10,  22},
+/* FPU */    {  0,  22,  22,    2,   10,   10,  22},
+/* ALL */    {  0,  22,  22,   22,   22,   22,  22}
 }  ;
 
 
 /* -- note that some moves are tremendously expensive, 
    because they require lots of tricks! do we have to 
    charge the costs incurred by secondary reload class 
-   -- as we do here with 22 -- or not ? */
+   -- as we do here with 10 -- or not ? */
 
-int 
-pdp11_register_move_cost (enum reg_class c1, enum reg_class c2)
+static int 
+pdp11_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
+			  reg_class_t c1, reg_class_t c2)
 {
     return move_costs[(int)c1][(int)c2];
 }
@@ -1634,6 +1645,108 @@
   return 0;
 }
 
+/* Implement CANNOT_CHANGE_MODE_CLASS.  */
+bool
+pdp11_cannot_change_mode_class (enum machine_mode from,
+				enum machine_mode to,
+				enum reg_class rclass)
+{
+  /* Also, FPU registers contain a whole float value and the parts of
+     it are not separately accessible.
+
+     So we disallow all mode changes involving FPRs.  */
+  if (FLOAT_MODE_P (from) != FLOAT_MODE_P (to))
+    return true;
+  
+  return reg_classes_intersect_p (FPU_REGS, rclass);
+}
+
+/* TARGET_PREFERRED_RELOAD_CLASS
+
+   Given an rtx X being reloaded into a reg required to be
+   in class CLASS, return the class of reg to actually use.
+   In general this is just CLASS; but on some machines
+   in some cases it is preferable to use a more restrictive class.  
+
+loading is easier into LOAD_FPU_REGS than FPU_REGS! */
+
+static reg_class_t
+pdp11_preferred_reload_class (rtx x, reg_class_t class)
+{
+  if (class == FPU_REGS)
+    return LOAD_FPU_REGS;
+  if (class == ALL_REGS)
+    {
+      if (FLOAT_MODE_P (GET_MODE (x)))
+	return LOAD_FPU_REGS;
+      else
+	return GENERAL_REGS;
+    }
+  return class;
+}
+
+/* TARGET_PREFERRED_OUTPUT_RELOAD_CLASS
+
+   Given an rtx X being reloaded into a reg required to be
+   in class CLASS, return the class of reg to actually use.
+   In general this is just CLASS; but on some machines
+   in some cases it is preferable to use a more restrictive class.  
+
+loading is easier into LOAD_FPU_REGS than FPU_REGS! */
+
+static reg_class_t
+pdp11_preferred_output_reload_class (rtx x, reg_class_t class)
+{
+  if (class == FPU_REGS)
+    return LOAD_FPU_REGS;
+  if (class == ALL_REGS)
+    {
+      if (FLOAT_MODE_P (GET_MODE (x)))
+	return LOAD_FPU_REGS;
+      else
+	return GENERAL_REGS;
+    }
+  return class;
+}
+
+
+/* TARGET_SECONDARY_RELOAD.
+
+   FPU registers AC4 and AC5 (class NO_LOAD_FPU_REGS) require an 
+   intermediate register (AC0-AC3: LOAD_FPU_REGS).  Everything else
+   can be loade/stored directly.  */
+reg_class_t 
+pdp11_secondary_reload (bool in_p ATTRIBUTE_UNUSED,
+			rtx x,
+			reg_class_t reload_class,
+			enum machine_mode reload_mode ATTRIBUTE_UNUSED,
+			secondary_reload_info *sri ATTRIBUTE_UNUSED)
+{
+  if (reload_class != NO_LOAD_FPU_REGS || GET_CODE (x) != REG ||
+      REGNO_REG_CLASS (REGNO (x)) == LOAD_FPU_REGS)
+    return NO_REGS;
+  
+  return LOAD_FPU_REGS;
+}
+
+/* Target routine to check if register to register move requires memory.
+
+   The answer is yes if we're going between general register and FPU 
+   registers.  The mode doesn't matter in making this check.
+*/
+bool 
+pdp11_secondary_memory_needed (reg_class_t c1, reg_class_t c2, 
+			       enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  int fromfloat = (c1 == LOAD_FPU_REGS || c1 == NO_LOAD_FPU_REGS || 
+		   c1 == FPU_REGS);
+  int tofloat = (c2 == LOAD_FPU_REGS || c2 == NO_LOAD_FPU_REGS || 
+		 c2 == FPU_REGS);
+  
+  return (fromfloat != tofloat);
+}
+
+
 /* A copy of output_addr_const modified for pdp11 expression syntax.
    output_addr_const also gets called for %cDIGIT and %nDIGIT, which we don't
    use, and for debugging output, which we don't support with this port either.
@@ -1751,7 +1864,7 @@
      ac0 if DFmode and FPU present - compatibility problem with
      libraries for non-floating point....  */
   return (TYPE_MODE (type) == DImode
-	  || (TYPE_MODE (type) == DFmode && ! TARGET_AC0));
+	  || (FLOAT_MODE_P (TYPE_MODE (type)) && ! TARGET_AC0));
 }
 
 /* Worker function for TARGET_FUNCTION_VALUE.
@@ -1854,3 +1967,5 @@
 	   ? GET_MODE_SIZE (mode)
 	   : int_size_in_bytes (type));
 }
+
+struct gcc_target targetm = TARGET_INITIALIZER;
Index: config/pdp11/pdp11.h
===================================================================
--- config/pdp11/pdp11.h	(revision 165973)
+++ config/pdp11/pdp11.h	(working copy)
@@ -215,15 +215,19 @@
     
 
 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
-   On the pdp, the cpu registers can hold any mode - check alignment
+   On the pdp, the cpu registers can hold any mode other than float
+   (because otherwise we may end up being asked to move from CPU to FPU
+   register, which isn't a valid operation on the PDP11).
+   For CPU registers, check alignment.
 
-   FPU can only hold DF - simplifies life!
+   FPU accepts SF and DF but actually holds a DF - simplifies life!
 */
 #define HARD_REGNO_MODE_OK(REGNO, MODE) \
 (((REGNO) <= PC_REGNUM)?				\
   ((GET_MODE_BITSIZE(MODE) <= 16) 			\
-   || (GET_MODE_BITSIZE(MODE) >= 32 && !((REGNO) & 1)))	\
-  :(MODE) == DFmode)
+   || (GET_MODE_BITSIZE(MODE) >= 32 &&      		\
+       !((REGNO) & 1) && !FLOAT_MODE_P (MODE)))		\
+  :FLOAT_MODE_P (MODE))
     
 
 /* Value is 1 if it is a good idea to tie two pseudo registers
@@ -322,19 +326,10 @@
 
 #define IRA_COVER_CLASSES { GENERAL_REGS, FPU_REGS, LIM_REG_CLASSES }
 
-/* Given an rtx X being reloaded into a reg required to be
-   in class CLASS, return the class of reg to actually use.
-   In general this is just CLASS; but on some machines
-   in some cases it is preferable to use a more restrictive class.  
+/* Hook for testing if memory is needed for moving between registers.  */
+#define SECONDARY_MEMORY_NEEDED(class1, class2, m) \
+  pdp11_secondary_memory_needed (class1, class2, m)
 
-loading is easier into LOAD_FPU_REGS than FPU_REGS! */
-
-#define PREFERRED_RELOAD_CLASS(X,CLASS) 	\
-(((CLASS) != FPU_REGS)?(CLASS):LOAD_FPU_REGS)
-
-#define SECONDARY_RELOAD_CLASS(CLASS,MODE,x)	\
-(((CLASS) == NO_LOAD_FPU_REGS && !(REG_P(x) && LOAD_FPU_REG_P(REGNO(x))))?LOAD_FPU_REGS:NO_REGS)
-
 /* Return the maximum number of consecutive registers
    needed to represent mode MODE in a register of class CLASS.  */
 #define CLASS_MAX_NREGS(CLASS, MODE)	\
@@ -343,6 +338,8 @@
   1									\
 )
 
+#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
+  pdp11_cannot_change_mode_class (FROM, TO, CLASS)
 
 /* Stack layout; function entry, exit and calling.  */
 
@@ -386,7 +383,7 @@
    If the precise function being called is known, FUNC is its FUNCTION_DECL;
    otherwise, FUNC is 0.  */
 #define BASE_RETURN_VALUE_REG(MODE) \
- ((MODE) == DFmode ? 8 : 0) 
+ (FLOAT_MODE_P (MODE) ? AC0_REGNUM : RETVAL_REGNUM) 
 
 /* 1 if N is a possible register number for function argument passing.
    - not used on pdp */
@@ -674,10 +671,6 @@
 /* #define NO_FUNCTION_CSE */
 
 
-/* cost of moving one register class to another */
-#define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2) \
-  pdp11_register_move_cost (CLASS1, CLASS2)
-
 /* Tell emit-rtl.c how to initialize special values on a per-function base.  */
 extern struct rtx_def *cc0_reg_rtx;
 
