Index: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c	2010-07-18 13:03:50.000000000 +0100
+++ gcc/config/mips/mips.c	2010-07-18 13:03:52.000000000 +0100
@@ -6318,19 +6318,28 @@ mips16_build_call_stub (rtx retval, rtx
 	  switch (GET_MODE (retval))
 	    {
 	    case SCmode:
-	      mips_output_32bit_xfer ('f', GP_RETURN + 1,
-				      FP_REG_FIRST + MAX_FPRS_PER_FMT);
-	      /* Fall though.  */
-	    case SFmode:
-	      mips_output_32bit_xfer ('f', GP_RETURN, FP_REG_FIRST);
+	      mips_output_32bit_xfer ('f', GP_RETURN + TARGET_BIG_ENDIAN,
+				      TARGET_BIG_ENDIAN
+				      ? FP_REG_FIRST + MAX_FPRS_PER_FMT
+				      : FP_REG_FIRST);
+	      mips_output_32bit_xfer ('f', GP_RETURN + TARGET_LITTLE_ENDIAN,
+				      TARGET_LITTLE_ENDIAN
+				      ? FP_REG_FIRST + MAX_FPRS_PER_FMT
+				      : FP_REG_FIRST);
 	      if (GET_MODE (retval) == SCmode && TARGET_64BIT)
 		{
 		  /* On 64-bit targets, complex floats are returned in
 		     a single GPR, such that "sd" on a suitably-aligned
 		     target would store the value correctly.  */
 		  fprintf (asm_out_file, "\tdsll\t%s,%s,32\n",
+			   reg_names[GP_RETURN + TARGET_BIG_ENDIAN],
+			   reg_names[GP_RETURN + TARGET_BIG_ENDIAN]);
+		  fprintf (asm_out_file, "\tdsll\t%s,%s,32\n",
 			   reg_names[GP_RETURN + TARGET_LITTLE_ENDIAN],
 			   reg_names[GP_RETURN + TARGET_LITTLE_ENDIAN]);
+		  fprintf (asm_out_file, "\tdsrl\t%s,%s,32\n",
+			   reg_names[GP_RETURN + TARGET_BIG_ENDIAN],
+			   reg_names[GP_RETURN + TARGET_BIG_ENDIAN]);
 		  fprintf (asm_out_file, "\tor\t%s,%s,%s\n",
 			   reg_names[GP_RETURN],
 			   reg_names[GP_RETURN],
@@ -6338,6 +6347,10 @@ mips16_build_call_stub (rtx retval, rtx
 		}
 	      break;
 
+	    case SFmode:
+	      mips_output_32bit_xfer ('f', GP_RETURN, FP_REG_FIRST);
+	      break;
+
 	    case DCmode:
 	      mips_output_64bit_xfer ('f', GP_RETURN + (8 / UNITS_PER_WORD),
 				      FP_REG_FIRST + MAX_FPRS_PER_FMT);
Index: gcc/config/mips/mips16.S
===================================================================
--- gcc/config/mips/mips16.S	2010-07-18 13:03:50.000000000 +0100
+++ gcc/config/mips/mips16.S	2010-07-18 13:03:52.000000000 +0100
@@ -61,9 +61,11 @@ see the files COPYING3 and COPYING.RUNTI
    and so that its low 32 bits contain LOW_FPR.  */
 #define MERGE_GPRf(GPR, HIGH_FPR, LOW_FPR)	\
 	.set	noat;				\
-	mfc1	GPR, HIGH_FPR;			\
 	mfc1	$1, LOW_FPR;			\
+	mfc1	GPR, HIGH_FPR;			\
+	dsll	$1, $1, 32;			\
 	dsll	GPR, GPR, 32;			\
+	dsrl	$1, $1, 32;			\
 	or	GPR, GPR, $1;			\
 	.set	at
 
Index: gcc/testsuite/gcc.target/mips/mips16-attributes-4.c
===================================================================
--- /dev/null	2010-07-18 09:23:39.222094797 +0100
+++ gcc/testsuite/gcc.target/mips/mips16-attributes-4.c	2010-07-18 13:03:52.000000000 +0100
@@ -0,0 +1,17 @@
+/* { dg-do run } */
+/* { dg-options "(-mips16)" } */
+
+extern void abort (void);
+
+__complex float f = { -1.0 + -1.0i };
+__complex float __attribute__((nomips16)) foo (void) { return f; }
+__complex float (*volatile foop) (void) = foo;
+__complex float __attribute__((mips16, noinline)) bar (void) { return foop (); }
+
+int
+main (void)
+{
+  if (bar () != f)
+    abort ();
+  return 0;
+}
