diff --git a/gcc/config/rs6000/constraints.md b/gcc/config/rs6000/constraints.md
index 90aba1e77d3..21c7a808919 100644
--- a/gcc/config/rs6000/constraints.md
+++ b/gcc/config/rs6000/constraints.md
@@ -252,7 +252,8 @@ (define_constraint "P"
   (and (match_code "const_int")
        (match_test "((- (unsigned HOST_WIDE_INT) ival) + 0x8000) < 0x10000")))
 
-;; Floating-point constraints
+;; Floating-point constraints.  These two are defined so that insn
+;; length attributes can be calculated exactly.
 
 (define_constraint "G"
   "Constant that can be copied into GPR with two insns for DF/DI
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index 1dfe7995ff1..dfee1f28aa9 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -36,7 +36,6 @@ extern int vspltis_shifted (rtx);
 extern HOST_WIDE_INT const_vector_elt_as_int (rtx, unsigned int);
 extern bool macho_lo_sum_memory_operand (rtx, machine_mode);
 extern int num_insns_constant (rtx, machine_mode);
-extern int num_insns_constant_wide (HOST_WIDE_INT);
 extern int small_data_operand (rtx, machine_mode);
 extern bool mem_operand_gpr (rtx, machine_mode);
 extern bool mem_operand_ds_form (rtx, machine_mode);
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 479dae547fa..1eabf9cd612 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -5818,7 +5818,7 @@ direct_return (void)
 /* Return the number of instructions it takes to form a constant in an
    integer register.  */
 
-int
+static int
 num_insns_constant_wide (HOST_WIDE_INT value)
 {
   /* signed constant loadable with addi */
@@ -5856,16 +5856,13 @@ num_insns_constant_wide (HOST_WIDE_INT value)
 int
 num_insns_constant (rtx op, machine_mode mode)
 {
-  HOST_WIDE_INT low, high;
+  HOST_WIDE_INT val;
 
   switch (GET_CODE (op))
     {
     case CONST_INT:
-      if ((INTVAL (op) >> 31) != 0 && (INTVAL (op) >> 31) != -1
-	  && rs6000_is_valid_and_mask (op, mode))
-	return 2;
-      else
-	return num_insns_constant_wide (INTVAL (op));
+      val = INTVAL (op);
+      break;
 
     case CONST_WIDE_INT:
       {
@@ -5876,50 +5873,62 @@ num_insns_constant (rtx op, machine_mode mode)
 	return ins;
       }
 
-      case CONST_DOUBLE:
+    case CONST_DOUBLE:
+      {
+	const struct real_value *rv = CONST_DOUBLE_REAL_VALUE (op);
+
 	if (mode == SFmode || mode == SDmode)
 	  {
 	    long l;
 
-	    if (DECIMAL_FLOAT_MODE_P (mode))
-	      REAL_VALUE_TO_TARGET_DECIMAL32
-		(*CONST_DOUBLE_REAL_VALUE (op), l);
+	    if (mode == SDmode)
+	      REAL_VALUE_TO_TARGET_DECIMAL32 (*rv, l);
 	    else
-	      REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op), l);
-	    return num_insns_constant_wide ((HOST_WIDE_INT) l);
+	      REAL_VALUE_TO_TARGET_SINGLE (*rv, l);
+	    /* See the first define_split in rs6000.md handling a
+	       const_double_operand.  */
+	    val = l;
+	    mode = SImode;
 	  }
-
-	long l[2];
-	if (DECIMAL_FLOAT_MODE_P (mode))
-	  REAL_VALUE_TO_TARGET_DECIMAL64 (*CONST_DOUBLE_REAL_VALUE (op), l);
-	else
-	  REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (op), l);
-	high = l[WORDS_BIG_ENDIAN == 0];
-	low  = l[WORDS_BIG_ENDIAN != 0];
-
-	if (TARGET_32BIT)
-	  return (num_insns_constant_wide (low)
-		  + num_insns_constant_wide (high));
-	else
+	else if (mode == DFmode || mode == DDmode)
 	  {
-	    if ((high == 0 && low >= 0)
-		|| (high == -1 && low < 0))
-	      return num_insns_constant_wide (low);
-
-	    else if (rs6000_is_valid_and_mask (op, mode))
-	      return 2;
-
-	    else if (low == 0)
-	      return num_insns_constant_wide (high) + 1;
+	    long l[2];
 
+	    if (mode == DDmode)
+	      REAL_VALUE_TO_TARGET_DECIMAL64 (*rv, l);
 	    else
-	      return (num_insns_constant_wide (high)
-		      + num_insns_constant_wide (low) + 1);
+	      REAL_VALUE_TO_TARGET_DOUBLE (*rv, l);
+
+	    HOST_WIDE_INT high = l[WORDS_BIG_ENDIAN == 0];
+	    HOST_WIDE_INT low  = l[WORDS_BIG_ENDIAN != 0];
+
+	    if (TARGET_32BIT)
+	      /* We'll be loading the double into two registers.
+		 See the second define_split in rs6000.md handling a
+		 const_double_operand.  */
+	      return (num_insns_constant_wide (low)
+		      + num_insns_constant_wide (high));
+
+	    /* See the third define_split in rs6000.md handling a
+	       const_double_operand.  */
+	    val = (low & 0xffffffffUL) | (high << 32);
+	    mode = DImode;
 	  }
+	else
+	  gcc_unreachable ();
+	op = NULL_RTX;
+      }
+      break;
 
     default:
       gcc_unreachable ();
     }
+
+  int ins = num_insns_constant_wide (val);
+  if (ins > 2
+      && rs6000_is_valid_and_mask (op ? op : GEN_INT (val), mode))
+    ins =  2;
+  return ins;
 }
 
 /* Interpret element ELT of the CONST_VECTOR OP as an integer value.
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 8e50f5b822b..0a16b1f5d41 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -7713,7 +7713,7 @@ (define_insn_and_split "*mov<mode>_32bit"
 
 (define_insn_and_split "*mov<mode>_softfloat"
   [(set (match_operand:FMOVE128 0 "nonimmediate_operand" "=Y,r,r")
-	(match_operand:FMOVE128 1 "input_operand" "r,YGHF,r"))]
+	(match_operand:FMOVE128 1 "input_operand" "r,Y,r"))]
   "TARGET_SOFT_FLOAT
    && (gpc_reg_operand (operands[0], <MODE>mode)
        || gpc_reg_operand (operands[1], <MODE>mode))"
@@ -8670,7 +8670,7 @@ (define_insn "*movdi_internal32"
 
 	(match_operand:DI 1 "input_operand"
          "r,         Y,         r,         ^d,        m,          ^d,
-          IJKnGHF,   ^wb,       $wv,       wY,        Z,          ^wi,
+          IJKnF,     ^wb,       $wv,       wY,        Z,          ^wi,
           Oj,        wM,        OjwM,      Oj,        wM,         wS,
           wB"))]
 
