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]

MIPS patch: complex returns and -msingle-float


Complex floats and doubles aren't returned properly on MIPS if
-msingle-float.  A single complex should be returned in ($f0, $f1),
a double complex should be returned in integer registers.  Existing
test cases are enough to show the problem (e.g. execute/complex-5.c).

It's easy to forget to check MASK_SINGLE_FLOAT, so the patch adds
two new macros in the UNITS_PER_FPREG vein.  It retrofits them to
a few places in mips.c, and does a few "clean ups" (be afraid!).

Tested on mips64-elf, no regressions.  OK to apply?

Richard


	* config/mips/mips.h (FP_INC, UNITS_PER_FPVALUE): New macros.
	* config/mips/mips.c (compute_frame_size): Retrofit them here.
	(save_restore_insns, mips_expand_epilogue): And here.
	(build_mips16_call_stub): And here.
	(mips_function_value): Use the new macros to decide whether a single
	or complex float can be returned in floating-point registers.  Return
	a parallel rtx in the complex case.

Index: config/mips/mips.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.h,v
retrieving revision 1.162
diff -c -p -d -r1.162 mips.h
*** config/mips/mips.h	2002/03/09 01:13:28	1.162
--- config/mips/mips.h	2002/03/13 10:36:30
*************** do {							\
*** 1591,1596 ****
--- 1591,1603 ----
  /* For MIPS, width of a floating point register.  */
  #define UNITS_PER_FPREG (TARGET_FLOAT64 ? 8 : 4)
  
+ /* If register $f0 holds a floating-point value, $f(0 + FP_INC) is
+    the next available register.  */
+ #define FP_INC (TARGET_FLOAT64 || TARGET_SINGLE_FLOAT ? 1 : 2)
+ 
+ /* The largest size of value that can be held in floating-point registers.  */
+ #define UNITS_PER_FPVALUE (FP_INC * UNITS_PER_FPREG)
+ 
  /* A C expression for the size in bits of the type `int' on the
     target machine.  If you don't define this, the default is one
     word.  */
Index: config/mips/mips.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.c,v
retrieving revision 1.181
diff -c -p -d -r1.181 mips.c
*** config/mips/mips.c	2002/03/10 01:38:59	1.181
--- config/mips/mips.c	2002/03/13 10:36:31
*************** compute_frame_size (size)
*** 6362,6367 ****
--- 6362,6368 ----
    long fmask;			/* mask of saved fp registers */
    int  fp_inc;			/* 1 or 2 depending on the size of fp regs */
    long fp_bits;			/* bitmask to use for each fp register */
+   tree return_type;
  
    gp_reg_size = 0;
    fp_reg_size = 0;
*************** compute_frame_size (size)
*** 6380,6385 ****
--- 6381,6387 ----
      args_size = 4 * UNITS_PER_WORD;
  
    total_size = var_size + args_size + extra_size;
+   return_type = DECL_RESULT (current_function_decl);
  
    /* Calculate space needed for gp registers.  */
    for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
*************** compute_frame_size (size)
*** 6398,6409 ****
  	      && regno == GP_REG_FIRST + 31
  	      && mips16_hard_float
  	      && ! mips_entry
! 	      && ! aggregate_value_p (DECL_RESULT (current_function_decl))
! 	      && (GET_MODE_CLASS (DECL_MODE (DECL_RESULT (current_function_decl)))
! 		  == MODE_FLOAT)
! 	      && (! TARGET_SINGLE_FLOAT
! 		  || (GET_MODE_SIZE (DECL_MODE (DECL_RESULT (current_function_decl)))
! 		      <= 4))))
  	{
  	  gp_reg_size += GET_MODE_SIZE (gpr_mode);
  	  mask |= 1L << (regno - GP_REG_FIRST);
--- 6400,6408 ----
  	      && regno == GP_REG_FIRST + 31
  	      && mips16_hard_float
  	      && ! mips_entry
! 	      && ! aggregate_value_p (return_type)
! 	      && GET_MODE_CLASS (DECL_MODE (return_type)) == MODE_FLOAT
! 	      && GET_MODE_SIZE (DECL_MODE (return_type)) <= UNITS_PER_FPVALUE))
  	{
  	  gp_reg_size += GET_MODE_SIZE (gpr_mode);
  	  mask |= 1L << (regno - GP_REG_FIRST);
*************** save_restore_insns (store_p, large_reg, 
*** 6854,6865 ****
    /* Save floating point registers if needed.  */
    if (fmask)
      {
-       int fp_inc = (TARGET_FLOAT64 || TARGET_SINGLE_FLOAT) ? 1 : 2;
-       int fp_size = fp_inc * UNITS_PER_FPREG;
- 
        /* Pick which pointer to use as a base register.  */
        fp_offset = current_frame_info.fp_sp_offset;
!       end_offset = fp_offset - (current_frame_info.fp_reg_size - fp_size);
  
        if (fp_offset < 0 || end_offset < 0)
  	internal_error
--- 6853,6862 ----
    /* Save floating point registers if needed.  */
    if (fmask)
      {
        /* Pick which pointer to use as a base register.  */
        fp_offset = current_frame_info.fp_sp_offset;
!       end_offset = fp_offset - (current_frame_info.fp_reg_size
! 				- UNITS_PER_FPVALUE);
  
        if (fp_offset < 0 || end_offset < 0)
  	internal_error
*************** save_restore_insns (store_p, large_reg, 
*** 6905,6913 ****
  
        /* This loop must iterate over the same space as its companion in
  	 compute_frame_size.  */
!       for (regno = (FP_REG_LAST - fp_inc + 1);
  	   regno >= FP_REG_FIRST;
! 	   regno -= fp_inc)
  	if (BITSET_P (fmask, regno - FP_REG_FIRST))
  	  {
  	    if (file == 0)
--- 6902,6910 ----
  
        /* This loop must iterate over the same space as its companion in
  	 compute_frame_size.  */
!       for (regno = (FP_REG_LAST - FP_INC + 1);
  	   regno >= FP_REG_FIRST;
! 	   regno -= FP_INC)
  	if (BITSET_P (fmask, regno - FP_REG_FIRST))
  	  {
  	    if (file == 0)
*************** save_restore_insns (store_p, large_reg, 
*** 6939,6945 ****
  		fprintf (file, "(%s)\n", reg_names[REGNO(base_reg_rtx)]);
  	      }
  
! 	    fp_offset -= fp_size;
  	  }
      }
  }
--- 6936,6942 ----
  		fprintf (file, "(%s)\n", reg_names[REGNO(base_reg_rtx)]);
  	      }
  
! 	    fp_offset -= UNITS_PER_FPVALUE;
  	  }
      }
  }
*************** mips_expand_epilogue ()
*** 7769,7791 ****
  int
  mips_can_use_return_insn ()
  {
    if (! reload_completed)
      return 0;
  
    if (regs_ever_live[31] || current_function_profile)
      return 0;
  
    /* In mips16 mode, a function which returns a floating point value
       needs to arrange to copy the return value into the floating point
       registers.  */
    if (TARGET_MIPS16
        && mips16_hard_float
!       && ! aggregate_value_p (DECL_RESULT (current_function_decl))
!       && (GET_MODE_CLASS (DECL_MODE (DECL_RESULT (current_function_decl)))
! 	  == MODE_FLOAT)
!       && (! TARGET_SINGLE_FLOAT
! 	  || (GET_MODE_SIZE (DECL_MODE (DECL_RESULT (current_function_decl)))
! 	      <= 4)))
      return 0;
  
    if (current_frame_info.initialized)
--- 7766,7789 ----
  int
  mips_can_use_return_insn ()
  {
+   tree return_type;
+ 
    if (! reload_completed)
      return 0;
  
    if (regs_ever_live[31] || current_function_profile)
      return 0;
  
+   return_type = DECL_RESULT (current_function_decl);
+ 
    /* In mips16 mode, a function which returns a floating point value
       needs to arrange to copy the return value into the floating point
       registers.  */
    if (TARGET_MIPS16
        && mips16_hard_float
!       && ! aggregate_value_p (return_type)
!       && GET_MODE_CLASS (DECL_MODE (return_type)) == MODE_FLOAT
!       && GET_MODE_SIZE (DECL_MODE (return_type)) <= UNITS_PER_FPVALUE)
      return 0;
  
    if (current_frame_info.initialized)
*************** mips_function_value (valtype, func)
*** 7951,7991 ****
       just as PROMOTE_MODE does.  */
    mode = promote_mode (valtype, mode, &unsignedp, 1);
  
!   if (mclass == MODE_FLOAT)
!     {
!       if (TARGET_SINGLE_FLOAT
! 	  && (mclass == MODE_FLOAT
! 	      ? GET_MODE_SIZE (mode) > 4 : GET_MODE_SIZE (mode) / 2 > 4))
! 	reg = GP_RETURN;
!       else
! 	reg = FP_RETURN;
!     }
  
!   else if (mclass == MODE_COMPLEX_FLOAT)
      {
!       if (TARGET_FLOAT64)
! 	reg = FP_RETURN;
!       else if (mode == SCmode)
! 	{
! 	  /* When FP registers are 32 bits, we can't directly reference
! 	     the odd numbered ones, so let's make a pair of evens.  */
! 
! 	  enum machine_mode cmode = TYPE_MODE (TREE_TYPE (valtype));
  
! 	  return gen_rtx_PARALLEL
! 	    (VOIDmode,
! 	     gen_rtvec (2,
! 			gen_rtx_EXPR_LIST (VOIDmode,
! 					   gen_rtx_REG (cmode,
! 							FP_RETURN),
! 					   GEN_INT (0)),
! 			gen_rtx_EXPR_LIST (VOIDmode,
! 					   gen_rtx_REG (cmode,
! 							FP_RETURN + 2),
! 					   GEN_INT (4))));
! 	}
!       else
! 	reg = FP_RETURN;
      }
  
    else if (TREE_CODE (valtype) == RECORD_TYPE
--- 7949,7971 ----
       just as PROMOTE_MODE does.  */
    mode = promote_mode (valtype, mode, &unsignedp, 1);
  
!   if (mclass == MODE_FLOAT && GET_MODE_SIZE (mode) <= UNITS_PER_FPVALUE)
!     reg = FP_RETURN;
  
!   else if (mclass == MODE_COMPLEX_FLOAT
! 	   && GET_MODE_SIZE (mode) <= UNITS_PER_FPVALUE * 2)
      {
!       enum machine_mode cmode = TYPE_MODE (TREE_TYPE (valtype));
  
!       return gen_rtx_PARALLEL
! 	(VOIDmode,
! 	 gen_rtvec (2,
! 		    gen_rtx_EXPR_LIST (VOIDmode,
! 				       gen_rtx_REG (cmode, FP_RETURN),
! 				       GEN_INT (0)),
! 		    gen_rtx_EXPR_LIST (VOIDmode,
! 				       gen_rtx_REG (cmode, FP_RETURN + FP_INC),
! 				       GEN_INT (GET_MODE_SIZE (cmode)))));
      }
  
    else if (TREE_CODE (valtype) == RECORD_TYPE
*************** build_mips16_call_stub (retval, fnmem, a
*** 8680,8687 ****
       register.  */
    fpret = (retval != 0
  	   && GET_MODE_CLASS (GET_MODE (retval)) == MODE_FLOAT
! 	   && (! TARGET_SINGLE_FLOAT
! 	       || GET_MODE_SIZE (GET_MODE (retval)) <= 4));
  
    /* We don't need to do anything if there were no floating point
       arguments and the value will not be returned in a floating point
--- 8660,8666 ----
       register.  */
    fpret = (retval != 0
  	   && GET_MODE_CLASS (GET_MODE (retval)) == MODE_FLOAT
! 	   && GET_MODE_SIZE (GET_MODE (retval)) <= UNITS_PER_FPVALUE);
  
    /* We don't need to do anything if there were no floating point
       arguments and the value will not be returned in a floating point


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