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] - Use of powerpc 64bit instructions in 32bit ABI


>>>>> Ian Lance Taylor writes:

Ian> For efficient 64-bit code, you want HARD_REGNO_NREGS (r, DImode) to
Ian> return 1.  But you also want to pass a 64-bit value in two registers,
Ian> to maintain ABI compatibility.  That means that you need a way to tell
Ian> the function calling sequence to split a 64-bit value into two 32-bit
Ian> values.

Ian> That of course can be done by having FUNCTION_ARG returning a
Ian> PARALLEL.  So, David (Edelsohn), I think that what you want is to
Ian> define HARD_REGNO_NREGS (r, DImode) to return 1 for a 64-bit register,
Ian> but also have FUNCTION_ARG return an appropriate PARALLEL when passing
Ian> a 64-bit value.  When passing a 32-bit value FUNCTION_ARG can just
Ian> return a REG as usual.

	I have committed the following patch which I bootstrapped without
regressions.  This is based on Fariborz original patch proposal, but
taking into account the recommendations from all of us to allow DImode in
GPRs while explicitly return PARALLELs for DFmode and DImode argument
passing.

	However, this design does not function properly when the 64-bit
computation / 32-bit ABI mode is enabled.  emit_group_{load,store} do not
generate the correct argument moves with word_mode remaining SImode.  At
least now we can focus on patches to fix emit_group_{load,store} and
friends.

David


	* config/rs6000/rs6000.h (UNITS_PER_WORD): Use TARGET_32BIT, not
	TARGET_POWREPC64.
	(UNITS_PER_GPR_WORD): Define.
	(HARD_REGNO_NREGS): Use UNITS_PER_GPR_WORD.
	(HARD_REGNO_CALL_PART_CLOBBERED): Define.
	(HARD_REGNO_MODE_OK): Use UNITS_PER_GPR_WORD.
	(CLASS_MAX_NREGS): Use UNITS_PER_GPR_WORD.
	* config/rs6000/rs6000.c (function_arg): Generate PARALLEL for
	DFmode and DImode in 32-bit ABI / 64-bit computation mode.
	(rs6000_emit_prologue): Select reg_mode and reg_size using
	TARGET_32BIT, not TARGET_POWERPC64.
	(rs6000_function_value): Generate PARALLEL for DImode in 32-bit
	ABI / 64-bit computation mode.

Index: rs6000.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.290
diff -c -p -r1.290 rs6000.h
*** rs6000.h	13 Oct 2003 21:16:31 -0000	1.290
--- rs6000.h	22 Oct 2003 20:21:13 -0000
*************** extern enum rs6000_dependence_cost rs600
*** 601,607 ****
  #define MAX_BITS_PER_WORD 64
  
  /* Width of a word, in units (bytes).  */
! #define UNITS_PER_WORD (! TARGET_POWERPC64 ? 4 : 8)
  #ifdef IN_LIBGCC2
  #define MIN_UNITS_PER_WORD UNITS_PER_WORD
  #else
--- 601,607 ----
  #define MAX_BITS_PER_WORD 64
  
  /* Width of a word, in units (bytes).  */
! #define UNITS_PER_WORD (TARGET_32BIT ? 4 : 8)
  #ifdef IN_LIBGCC2
  #define MIN_UNITS_PER_WORD UNITS_PER_WORD
  #else
*************** extern enum rs6000_dependence_cost rs600
*** 964,969 ****
--- 964,971 ----
     POWER and PowerPC GPRs hold 32 bits worth;
     PowerPC64 GPRs and FPRs point register holds 64 bits worth.  */
  
+ #define UNITS_PER_GPR_WORD (! TARGET_POWERPC64 ? 4 : 8)
+ 
  #define HARD_REGNO_NREGS(REGNO, MODE)					\
    (FP_REGNO_P (REGNO)							\
     ? ((GET_MODE_SIZE (MODE) + UNITS_PER_FP_WORD - 1) / UNITS_PER_FP_WORD) \
*************** extern enum rs6000_dependence_cost rs600
*** 971,977 ****
     ? ((GET_MODE_SIZE (MODE) + UNITS_PER_SPE_WORD - 1) / UNITS_PER_SPE_WORD) \
     : ALTIVEC_REGNO_P (REGNO)						\
     ? ((GET_MODE_SIZE (MODE) + UNITS_PER_ALTIVEC_WORD - 1) / UNITS_PER_ALTIVEC_WORD) \
!    : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
  
  #define ALTIVEC_VECTOR_MODE(MODE)	\
  	 ((MODE) == V16QImode		\
--- 973,984 ----
     ? ((GET_MODE_SIZE (MODE) + UNITS_PER_SPE_WORD - 1) / UNITS_PER_SPE_WORD) \
     : ALTIVEC_REGNO_P (REGNO)						\
     ? ((GET_MODE_SIZE (MODE) + UNITS_PER_ALTIVEC_WORD - 1) / UNITS_PER_ALTIVEC_WORD) \
!    : ((GET_MODE_SIZE (MODE) + UNITS_PER_GPR_WORD - 1) / UNITS_PER_GPR_WORD))
! 
! #define HARD_REGNO_CALL_PART_CLOBBERED(REGNO, MODE)	\
!   ((TARGET_32BIT && TARGET_POWERPC64			\
!     && (MODE == DImode || MODE == DFmode)		\
!     && INT_REGNO_P (REGNO)) ? 1 : 0)
  
  #define ALTIVEC_VECTOR_MODE(MODE)	\
  	 ((MODE) == V16QImode		\
*************** extern enum rs6000_dependence_cost rs600
*** 1011,1017 ****
     : SPE_SIMD_REGNO_P (REGNO) && TARGET_SPE && SPE_VECTOR_MODE (MODE) ? 1 \
     : CR_REGNO_P (REGNO) ? GET_MODE_CLASS (MODE) == MODE_CC		\
     : XER_REGNO_P (REGNO) ? (MODE) == PSImode				\
!    : GET_MODE_SIZE (MODE) <= UNITS_PER_WORD)
  
  /* Value is 1 if it is a good idea to tie two pseudo registers
     when one has mode MODE1 and one has mode MODE2.
--- 1018,1024 ----
     : SPE_SIMD_REGNO_P (REGNO) && TARGET_SPE && SPE_VECTOR_MODE (MODE) ? 1 \
     : CR_REGNO_P (REGNO) ? GET_MODE_CLASS (MODE) == MODE_CC		\
     : XER_REGNO_P (REGNO) ? (MODE) == PSImode				\
!    : GET_MODE_SIZE (MODE) <= UNITS_PER_GPR_WORD)
  
  /* Value is 1 if it is a good idea to tie two pseudo registers
     when one has mode MODE1 and one has mode MODE2.
*************** enum reg_class
*** 1434,1440 ****
  #define CLASS_MAX_NREGS(CLASS, MODE)					\
   (((CLASS) == FLOAT_REGS) 						\
    ? ((GET_MODE_SIZE (MODE) + UNITS_PER_FP_WORD - 1) / UNITS_PER_FP_WORD) \
!   : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
  
  
  /* Return a class of registers that cannot change FROM mode to TO mode.  */
--- 1441,1447 ----
  #define CLASS_MAX_NREGS(CLASS, MODE)					\
   (((CLASS) == FLOAT_REGS) 						\
    ? ((GET_MODE_SIZE (MODE) + UNITS_PER_FP_WORD - 1) / UNITS_PER_FP_WORD) \
!   : ((GET_MODE_SIZE (MODE) + UNITS_PER_GPR_WORD - 1) / UNITS_PER_GPR_WORD))
  
  
  /* Return a class of registers that cannot change FROM mode to TO mode.  */
Index: rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.534
diff -c -p -r1.534 rs6000.c
*** rs6000.c	17 Oct 2003 20:20:37 -0000	1.534
--- rs6000.c	22 Oct 2003 20:21:14 -0000
*************** function_arg (CUMULATIVE_ARGS *cum, enum
*** 4040,4045 ****
--- 4064,4116 ----
  		      || (align_words < GP_ARG_NUM_REG))))
  	    return gen_rtx_REG (mode, cum->fregno);
  
+ 	  if (TARGET_32BIT && TARGET_POWERPC64 && 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)));
+             }
+ 
            return gen_rtx_PARALLEL (mode,
  	    gen_rtvec (2,
  		       gen_rtx_EXPR_LIST (VOIDmode,
*************** function_arg (CUMULATIVE_ARGS *cum, enum
*** 4060,4065 ****
--- 4131,4167 ----
  				gen_rtx_REG (mode, cum->fregno),
  				const0_rtx)));
  	}
+       /* -mpowerpc64 with 32bit ABI splits up a DImode argument into one
+ 	 or two GPRs */
+       else if (TARGET_32BIT && TARGET_POWERPC64 && mode == DImode
+ 	       && 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 (TARGET_32BIT && TARGET_POWERPC64 && mode == DImode
+ 	       && 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 (align_words < GP_ARG_NUM_REG)
  	return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
        else
*************** void
*** 11247,11254 ****
  rs6000_emit_prologue (void)
  {
    rs6000_stack_t *info = rs6000_stack_info ();
!   enum machine_mode reg_mode = TARGET_POWERPC64 ? DImode : SImode;
!   int reg_size = TARGET_POWERPC64 ? 8 : 4;
    rtx sp_reg_rtx = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
    rtx frame_ptr_rtx = gen_rtx_REG (Pmode, 12);
    rtx frame_reg_rtx = sp_reg_rtx;
--- 11349,11356 ----
  rs6000_emit_prologue (void)
  {
    rs6000_stack_t *info = rs6000_stack_info ();
!   enum machine_mode reg_mode = Pmode;
!   int reg_size = UNITS_PER_WORD;
    rtx sp_reg_rtx = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
    rtx frame_ptr_rtx = gen_rtx_REG (Pmode, 12);
    rtx frame_reg_rtx = sp_reg_rtx;
*************** rs6000_emit_epilogue (int sibcall)
*** 11713,11720 ****
    int sp_offset = 0;
    rtx sp_reg_rtx = gen_rtx_REG (Pmode, 1);
    rtx frame_reg_rtx = sp_reg_rtx;
!   enum machine_mode reg_mode = TARGET_POWERPC64 ? DImode : SImode;
!   int reg_size = TARGET_POWERPC64 ? 8 : 4;
    int i;
  
    info = rs6000_stack_info ();
--- 11815,11822 ----
    int sp_offset = 0;
    rtx sp_reg_rtx = gen_rtx_REG (Pmode, 1);
    rtx frame_reg_rtx = sp_reg_rtx;
!   enum machine_mode reg_mode = Pmode;
!   int reg_size = UNITS_PER_WORD;
    int i;
  
    info = rs6000_stack_info ();
*************** rs6000_function_value (tree valtype, tre
*** 14839,14844 ****
--- 14963,14982 ----
  {
    enum machine_mode mode;
    unsigned int regno;
+ 
+   if (TARGET_32BIT && TARGET_POWERPC64 && TYPE_MODE (valtype) == DImode)
+     {
+       /* Long long return value need be split in -mpowerpc64, 32bit ABI.  */
+       return gen_rtx_PARALLEL (DImode,
+ 	gen_rtvec (2,
+ 		   gen_rtx_EXPR_LIST (VOIDmode,
+ 				      gen_rtx_REG (SImode, GP_ARG_RETURN),
+ 				      const0_rtx),
+ 		   gen_rtx_EXPR_LIST (VOIDmode,
+ 				      gen_rtx_REG (SImode,
+ 						   GP_ARG_RETURN + 1),
+ 				      GEN_INT (4))));
+     }
  
    if ((INTEGRAL_TYPE_P (valtype)
         && TYPE_PRECISION (valtype) < BITS_PER_WORD)


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