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]

Re: PATCH [mainline] - Fix passing of zero-sized structs in apple-ppc-darwin mixed mode


Here's the complete revised patch.

	* config/rs6000/rs6000.c (rs6000_mixed_function_arg): Rewrite.
	(function_arg): Use rs6000_arg_size rather than CLASS_MAX_NREGS in
	calculating gpr size for altivec.  Simplify and correct
	rs6000_mixed_function_arg calls.  Call rs6000_mixed_function_arg
	for ABI_V4 gpr case too.  Fix off-by-one error in long double
	reg test.  Generate the correct PARALLEL to handle long double
	for ABI_AIX 32-bit.  Use this for -m32 -mpowerpc64 fpr case too.
	(function_arg_partial_nregs): Align before calculating regs left.
	Don't return info on partial fprs when we need info on gprs.
	Correct long double fpr off-by-one error.

diff -crp -xCVS -x'*~' gcc-virgin/gcc/config/rs6000/rs6000.c gcc-mainline/gcc/config/rs6000/rs6000.c
*** gcc-virgin/gcc/config/rs6000/rs6000.c	2004-06-24 14:24:16.000000000 +0930
--- gcc-mainline/gcc/config/rs6000/rs6000.c	2004-06-28 09:19:48.099524794 +0930
*************** static rtx rs6000_dwarf_register_span (r
*** 425,432 ****
  static rtx rs6000_complex_function_value (enum machine_mode);
  static rtx rs6000_spe_function_arg (CUMULATIVE_ARGS *,
  				    enum machine_mode, tree);
! static rtx rs6000_mixed_function_arg (CUMULATIVE_ARGS *,
! 				      enum machine_mode, tree, int);
  static void rs6000_move_block_from_reg (int regno, rtx x, int nregs);
  static void setup_incoming_varargs (CUMULATIVE_ARGS *,
  				    enum machine_mode, tree,
--- 425,431 ----
  static rtx rs6000_complex_function_value (enum machine_mode);
  static rtx rs6000_spe_function_arg (CUMULATIVE_ARGS *,
  				    enum machine_mode, tree);
! static rtx rs6000_mixed_function_arg (enum machine_mode, tree, int);
  static void rs6000_move_block_from_reg (int regno, rtx x, int nregs);
  static void setup_incoming_varargs (CUMULATIVE_ARGS *,
  				    enum machine_mode, tree,
*************** rs6000_spe_function_arg (CUMULATIVE_ARGS
*** 4418,4541 ****
  /* Determine where to place an argument in 64-bit mode with 32-bit ABI.  */
  
  static rtx
! rs6000_mixed_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, 
! 			   tree type, int align_words)
  {
!   if (mode == DFmode)
      {
!       /* -mpowerpc64 with 32bit ABI splits up a DFmode argument
! 	 in vararg list into zero, one or two GPRs */
!       if (align_words >= GP_ARG_NUM_REG)
! 	return gen_rtx_PARALLEL (DFmode,
! 		 gen_rtvec (2,
! 			    gen_rtx_EXPR_LIST (VOIDmode,
! 					       NULL_RTX, const0_rtx), 
! 			    gen_rtx_EXPR_LIST (VOIDmode,
! 					       gen_rtx_REG (mode,
! 							    cum->fregno),
! 					       const0_rtx)));
!       else if (align_words + rs6000_arg_size (mode, type)
! 	       > GP_ARG_NUM_REG)
! 	/* If this is partially on the stack, then we only
! 	   include the portion actually in registers here.  */
! 	return gen_rtx_PARALLEL (DFmode,
! 		 gen_rtvec (2,   
! 			    gen_rtx_EXPR_LIST (VOIDmode,
! 					       gen_rtx_REG (SImode,
! 							    GP_ARG_MIN_REG
! 							    + align_words),
! 					       const0_rtx),
! 			    gen_rtx_EXPR_LIST (VOIDmode,
! 					       gen_rtx_REG (mode,
! 							    cum->fregno),
! 					       const0_rtx)));
! 
!       /* split a DFmode arg into two GPRs */
!       return gen_rtx_PARALLEL (DFmode,
! 	       gen_rtvec (3,
! 			  gen_rtx_EXPR_LIST (VOIDmode,       
! 					     gen_rtx_REG (SImode,
! 							  GP_ARG_MIN_REG
! 							  + align_words),
! 					     const0_rtx),
! 			  gen_rtx_EXPR_LIST (VOIDmode,
! 					     gen_rtx_REG (SImode,
! 							  GP_ARG_MIN_REG
! 							  + align_words + 1),
! 					     GEN_INT (4)),
! 			  gen_rtx_EXPR_LIST (VOIDmode,
! 					     gen_rtx_REG (mode, cum->fregno),
! 					     const0_rtx)));
      }
!   /* -mpowerpc64 with 32bit ABI splits up a DImode argument into one
!      or two GPRs */
!   else if (mode == DImode)
!     {
!       if (align_words < GP_ARG_NUM_REG - 1)
! 	return gen_rtx_PARALLEL (DImode,
! 		 gen_rtvec (2,
! 			    gen_rtx_EXPR_LIST (VOIDmode,
! 					       gen_rtx_REG (SImode,
! 							    GP_ARG_MIN_REG
! 							    + align_words),
! 					       const0_rtx),
! 			    gen_rtx_EXPR_LIST (VOIDmode,
! 					       gen_rtx_REG (SImode,
! 							    GP_ARG_MIN_REG
! 							    + align_words + 1),
! 					       GEN_INT (4))));
!       else if (align_words == GP_ARG_NUM_REG - 1)
! 	  return gen_rtx_PARALLEL (DImode,
! 		   gen_rtvec (2,
! 			      gen_rtx_EXPR_LIST (VOIDmode,
! 						 NULL_RTX, const0_rtx),
! 			      gen_rtx_EXPR_LIST (VOIDmode,
! 						 gen_rtx_REG (SImode,
! 							      GP_ARG_MIN_REG
! 							      + align_words),
! 						 const0_rtx)));
!     }
!   else if (ALTIVEC_VECTOR_MODE (mode) && align_words == GP_ARG_NUM_REG - 2)
!     {
!       /* Varargs vector regs must be saved in R9-R10.  */
!       return gen_rtx_PARALLEL (mode,
! 	   		       gen_rtvec (3,
! 			         gen_rtx_EXPR_LIST (VOIDmode,
! 						     NULL_RTX, const0_rtx),
! 			         gen_rtx_EXPR_LIST (VOIDmode,
! 						    gen_rtx_REG (SImode,
! 							         GP_ARG_MIN_REG
! 							         + align_words),
! 						    const0_rtx),
! 			         gen_rtx_EXPR_LIST (VOIDmode,
! 						    gen_rtx_REG (SImode,
! 							         GP_ARG_MIN_REG
! 							         + align_words + 1),
! 						    GEN_INT (4))));
!     }
!   else if ((mode == BLKmode || ALTIVEC_VECTOR_MODE (mode))
!            && align_words <= (GP_ARG_NUM_REG - 1))
!     {
!       /* AltiVec vector regs are saved in R5-R8. */
!       int k;
!       int size = int_size_in_bytes (type);
!       int no_units = ((size - 1) / 4) + 1;
!       int max_no_words = GP_ARG_NUM_REG - align_words;
!       int rtlvec_len = no_units < max_no_words ? no_units : max_no_words;
!       rtx *rtlvec = (rtx *) alloca (rtlvec_len * sizeof (rtx));
! 
!       memset ((char *) rtlvec, 0, rtlvec_len * sizeof (rtx));
! 
!       for (k=0; k < rtlvec_len; k++)
! 	rtlvec[k] = gen_rtx_EXPR_LIST (VOIDmode,
! 				       gen_rtx_REG (SImode,
! 						    GP_ARG_MIN_REG
! 						    + align_words + k),
! 				       k == 0 ? const0_rtx : GEN_INT (k*4));
  
!       return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rtlvec));
!     }
!   return NULL_RTX;
  }
  
  /* Determine where to put an argument to a function.
--- 4417,4465 ----
  /* Determine where to place an argument in 64-bit mode with 32-bit ABI.  */
  
  static rtx
! rs6000_mixed_function_arg (enum machine_mode mode, tree type, int align_words)
  {
!   int n_units;
!   int i, k;
!   rtx rvec[GP_ARG_NUM_REG + 1];
! 
!   if (align_words >= GP_ARG_NUM_REG)
!     return NULL_RTX;
! 
!   n_units = rs6000_arg_size (mode, type);
! 
!   /* Optimize the simple case where the arg fits in one gpr, except in
!      the case of BLKmode due to assign_parms assuming that registers are
!      BITS_PER_WORD wide.  */
!   if (n_units == 0
!       || (n_units == 1 && mode != BLKmode))
!     return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
! 
!   k = 0;
!   if (align_words + n_units > GP_ARG_NUM_REG)
!     /* Not all of the arg fits in gprs.  Say that it goes in memory too,
!        using a magic NULL_RTX component.
!        FIXME: This is not strictly correct.  Only some of the arg
!        belongs in memory, not all of it.  However, there isn't any way
!        to do this currently, apart from building rtx descriptions for
!        the pieces of memory we want stored.  Due to bugs in the generic
!        code we can't use the normal function_arg_partial_nregs scheme
!        with the PARALLEL arg description we emit here.
!        In any case, the code to store the whole arg to memory is often
!        more efficient than code to store pieces, and we know that space
!        is available in the right place for the whole arg.  */
!     rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
! 
!   i = 0;
!   do
      {
!       rtx r = gen_rtx_REG (SImode, GP_ARG_MIN_REG + align_words);
!       rtx off = GEN_INT (i++ * 4);
!       rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
      }
!   while (++align_words < GP_ARG_NUM_REG && --n_units != 0);
  
!   return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
  }
  
  /* Determine where to put an argument to a function.
*************** function_arg (CUMULATIVE_ARGS *cum, enum
*** 4630,4637 ****
  	{
  	  /* Vector parameters to varargs functions under AIX or Darwin
  	     get passed in memory and possibly also in GPRs.  */
! 	  int align, align_words;
! 	  enum machine_mode part_mode = mode;
  
  	  /* Vector parameters must be 16-byte aligned.  This places them at
  	     2 mod 4 in terms of words in 32-bit mode, since the parameter
--- 4554,4561 ----
  	{
  	  /* Vector parameters to varargs functions under AIX or Darwin
  	     get passed in memory and possibly also in GPRs.  */
! 	  int align, align_words, n_words;
! 	  enum machine_mode part_mode;
  
  	  /* Vector parameters must be 16-byte aligned.  This places them at
  	     2 mod 4 in terms of words in 32-bit mode, since the parameter
*************** function_arg (CUMULATIVE_ARGS *cum, enum
*** 4647,4666 ****
  	  /* Out of registers?  Memory, then.  */
  	  if (align_words >= GP_ARG_NUM_REG)
  	    return NULL_RTX;
! 	  
  	  /* The vector value goes in GPRs.  Only the part of the
  	     value in GPRs is reported here.  */
! 	  if (align_words + CLASS_MAX_NREGS (mode, GENERAL_REGS)
! 	      > GP_ARG_NUM_REG)
  	    /* Fortunately, there are only two possibilities, the value
  	       is either wholly in GPRs or half in GPRs and half not.  */
  	    part_mode = DImode;
! 	  
! 	  if (TARGET_32BIT
! 	      && (TARGET_POWERPC64 || (align_words == GP_ARG_NUM_REG - 2)))
! 	    return rs6000_mixed_function_arg (cum, part_mode, type, align_words);
! 	  else
! 	    return gen_rtx_REG (part_mode, GP_ARG_MIN_REG + align_words);
  	}
      }
    else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode))
--- 4571,4590 ----
  	  /* Out of registers?  Memory, then.  */
  	  if (align_words >= GP_ARG_NUM_REG)
  	    return NULL_RTX;
! 
! 	  if (TARGET_32BIT && TARGET_POWERPC64)
! 	    return rs6000_mixed_function_arg (mode, type, align_words);
! 
  	  /* The vector value goes in GPRs.  Only the part of the
  	     value in GPRs is reported here.  */
! 	  part_mode = mode;
! 	  n_words = rs6000_arg_size (mode, type);
! 	  if (align_words + n_words > GP_ARG_NUM_REG)
  	    /* Fortunately, there are only two possibilities, the value
  	       is either wholly in GPRs or half in GPRs and half not.  */
  	    part_mode = DImode;
! 
! 	  return gen_rtx_REG (part_mode, GP_ARG_MIN_REG + align_words);
  	}
      }
    else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode))
*************** function_arg (CUMULATIVE_ARGS *cum, enum
*** 4687,4696 ****
  	    gregno += (1 - gregno) & 1;
  
  	  /* Multi-reg args are not split between registers and stack.  */
! 	  if (gregno + n_words - 1 <= GP_ARG_MAX_REG)
! 	    return gen_rtx_REG (mode, gregno);
! 	  else
  	    return NULL_RTX;
  	}
      }
    else
--- 4611,4623 ----
  	    gregno += (1 - gregno) & 1;
  
  	  /* Multi-reg args are not split between registers and stack.  */
! 	  if (gregno + n_words - 1 > GP_ARG_MAX_REG)
  	    return NULL_RTX;
+ 
+ 	  if (TARGET_32BIT && TARGET_POWERPC64)
+ 	    return rs6000_mixed_function_arg (mode, type,
+ 					      gregno - GP_ARG_MIN_REG);
+ 	  return gen_rtx_REG (mode, gregno);
  	}
      }
    else
*************** function_arg (CUMULATIVE_ARGS *cum, enum
*** 4700,4724 ****
  
        if (USE_FP_FOR_ARG_P (cum, mode, type))
  	{
! 	  rtx fpr[2];
! 	  rtx *r;
  	  bool needs_psave;
  	  enum machine_mode fmode = mode;
- 	  int n;
  	  unsigned long n_fpreg = (GET_MODE_SIZE (mode) + 7) >> 3;
  
  	  if (cum->fregno + n_fpreg > FP_ARG_MAX_REG + 1)
  	    {
- 	      /* Long double split over regs and memory.  */
- 	      if (fmode == TFmode)
- 		fmode = DFmode;
- 
  	      /* Currently, we only ever need one reg here because complex
  		 doubles are split.  */
! 	      if (cum->fregno != FP_ARG_MAX_REG - 1)
  		abort ();
  	    }
- 	  fpr[1] = gen_rtx_REG (fmode, cum->fregno);
  
  	  /* Do we also need to pass this arg in the parameter save
  	     area?  */
--- 4627,4649 ----
  
        if (USE_FP_FOR_ARG_P (cum, mode, type))
  	{
! 	  rtx rvec[GP_ARG_NUM_REG + 1];
! 	  rtx r;
! 	  int k;
  	  bool needs_psave;
  	  enum machine_mode fmode = mode;
  	  unsigned long n_fpreg = (GET_MODE_SIZE (mode) + 7) >> 3;
  
  	  if (cum->fregno + n_fpreg > FP_ARG_MAX_REG + 1)
  	    {
  	      /* Currently, we only ever need one reg here because complex
  		 doubles are split.  */
! 	      if (cum->fregno != FP_ARG_MAX_REG || fmode != TFmode)
  		abort ();
+ 
+ 	      /* Long double split over regs and memory.  */
+ 	      fmode = DFmode;
  	    }
  
  	  /* Do we also need to pass this arg in the parameter save
  	     area?  */
*************** function_arg (CUMULATIVE_ARGS *cum, enum
*** 4729,4774 ****
  				 && align_words >= GP_ARG_NUM_REG)));
  
  	  if (!needs_psave && mode == fmode)
! 	    return fpr[1];
! 
!           if (TARGET_32BIT && TARGET_POWERPC64
!               && mode == DFmode && cum->stdarg)
!             return rs6000_mixed_function_arg (cum, mode, type, align_words);
! 
! 	  /* Describe where this piece goes.  */
! 	  r = fpr + 1;
! 	  *r = gen_rtx_EXPR_LIST (VOIDmode, *r, const0_rtx);
! 	  n = 1;
  
  	  if (needs_psave)
  	    {
! 	      /* Now describe the part that goes in gprs or the stack.
  		 This piece must come first, before the fprs.  */
- 	      rtx reg = NULL_RTX;
  	      if (align_words < GP_ARG_NUM_REG)
  		{
  		  unsigned long n_words = rs6000_arg_size (mode, type);
- 		  enum machine_mode rmode = mode;
  
! 		  if (align_words + n_words > GP_ARG_NUM_REG)
! 		    /* If this is partially on the stack, then we only
! 		       include the portion actually in registers here.
! 		       We know this can only be one register because
! 		       complex doubles are splt.  */
! 		    rmode = Pmode;
! 		  reg = gen_rtx_REG (rmode, GP_ARG_MIN_REG + align_words);
  		}
! 	      *--r = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx);
! 	      ++n;
  	    }
  
! 	  return gen_rtx_PARALLEL (mode, gen_rtvec_v (n, r));
  	}
        else if (align_words < GP_ARG_NUM_REG)
  	{
! 	  if (TARGET_32BIT && TARGET_POWERPC64
! 	      && (mode == DImode || mode == BLKmode))
! 	    return rs6000_mixed_function_arg (cum, mode, type, align_words);
  
  	  return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
  	}
--- 4654,4708 ----
  				 && align_words >= GP_ARG_NUM_REG)));
  
  	  if (!needs_psave && mode == fmode)
! 	    return gen_rtx_REG (fmode, cum->fregno);
  
+ 	  k = 0;
  	  if (needs_psave)
  	    {
! 	      /* Describe the part that goes in gprs or the stack.
  		 This piece must come first, before the fprs.  */
  	      if (align_words < GP_ARG_NUM_REG)
  		{
  		  unsigned long n_words = rs6000_arg_size (mode, type);
  
! 		  if (align_words + n_words > GP_ARG_NUM_REG
! 		      || (TARGET_32BIT && TARGET_POWERPC64))
! 		    {
! 		      /* If this is partially on the stack, then we only
! 			 include the portion actually in registers here.  */
! 		      enum machine_mode rmode = TARGET_32BIT ? SImode : DImode;
! 		      rtx off;
! 		      do
! 			{
! 			  r = gen_rtx_REG (rmode,
! 					   GP_ARG_MIN_REG + align_words);
! 			  off = GEN_INT (k * GET_MODE_SIZE (rmode));
! 			  rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
! 			}
! 		      while (++align_words < GP_ARG_NUM_REG && --n_words != 0);
! 		    }
! 		  else
! 		    {
! 		      /* The whole arg fits in gprs.  */
! 		      r = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
! 		      rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
! 		    }
  		}
! 	      else
! 		/* It's entirely in memory.  */
! 		rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
  	    }
  
! 	  /* Describe where this piece goes in the fprs.  */
! 	  r = gen_rtx_REG (fmode, cum->fregno);
! 	  rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
! 
! 	  return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
  	}
        else if (align_words < GP_ARG_NUM_REG)
  	{
! 	  if (TARGET_32BIT && TARGET_POWERPC64)
! 	    return rs6000_mixed_function_arg (mode, type, align_words);
  
  	  return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
  	}
*************** function_arg (CUMULATIVE_ARGS *cum, enum
*** 4777,4791 ****
      }
  }
  
! /* For an arg passed partly in registers and partly in memory,
!    this is the number of registers used.
!    For args passed entirely in registers or entirely in memory, zero.  */
  
  int
  function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode, 
  			    tree type, int named)
  {
    int ret = 0;
  
    if (DEFAULT_ABI == ABI_V4)
      return 0;
--- 4711,4730 ----
      }
  }
  
! /* For an arg passed partly in registers and partly in memory, this is
!    the number of registers used.  For args passed entirely in registers
!    or entirely in memory, zero.  When an arg is described by a PARALLEL,
!    perhaps using more than one register type, this function returns the
!    number of registers used by the first element of the PARALLEL.  */
  
  int
  function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode, 
  			    tree type, int named)
  {
    int ret = 0;
+   int align;
+   int parm_offset;
+   int align_words;
  
    if (DEFAULT_ABI == ABI_V4)
      return 0;
*************** function_arg_partial_nregs (CUMULATIVE_A
*** 4794,4810 ****
        && cum->nargs_prototype >= 0)
      return 0;
  
!   if (USE_FP_FOR_ARG_P (cum, mode, type))
      {
        if (cum->fregno + ((GET_MODE_SIZE (mode) + 7) >> 3) > FP_ARG_MAX_REG + 1)
! 	ret = FP_ARG_MAX_REG - cum->fregno;
        else if (cum->nargs_prototype >= 0)
  	return 0;
      }
  
!   if (cum->words < GP_ARG_NUM_REG
!       && GP_ARG_NUM_REG < cum->words + rs6000_arg_size (mode, type))
!     ret = GP_ARG_NUM_REG - cum->words;
  
    if (ret != 0 && TARGET_DEBUG_ARG)
      fprintf (stderr, "function_arg_partial_nregs: %d\n", ret);
--- 4733,4761 ----
        && cum->nargs_prototype >= 0)
      return 0;
  
!   align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
!   parm_offset = TARGET_32BIT ? 2 : 0;
!   align_words = cum->words + ((parm_offset - cum->words) & align);
! 
!   if (USE_FP_FOR_ARG_P (cum, mode, type)
!       /* If we are passing this arg in gprs as well, then this function
! 	 should return the number of gprs (or memory) partially passed,
! 	 *not* the number of fprs.  */
!       && !(type
! 	   && (cum->nargs_prototype <= 0
! 	       || (DEFAULT_ABI == ABI_AIX
! 		   && TARGET_XL_CALL
! 		   && align_words >= GP_ARG_NUM_REG))))
      {
        if (cum->fregno + ((GET_MODE_SIZE (mode) + 7) >> 3) > FP_ARG_MAX_REG + 1)
! 	ret = FP_ARG_MAX_REG + 1 - cum->fregno;
        else if (cum->nargs_prototype >= 0)
  	return 0;
      }
  
!   if (align_words < GP_ARG_NUM_REG
!       && GP_ARG_NUM_REG < align_words + rs6000_arg_size (mode, type))
!     ret = GP_ARG_NUM_REG - align_words;
  
    if (ret != 0 && TARGET_DEBUG_ARG)
      fprintf (stderr, "function_arg_partial_nregs: %d\n", ret);

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


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