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]

patch: e500 pass DF modes as -msoft-float


This patch implements the ABI requirement that doubles must go in a
pair of 32-bit GPRs, as -msoft-float currently does.  The trick is
achieved by passing a parallel of a DI register, which GCC will
magically put into two registers.  I.e. (parallel:DF (expr_list (reg:DI))).

Thanks to rth for coming up with this craziness.

There are also some SUBREG patterns that manipulate the registers
correctly, as GCC can get confused with subreg's of DFmode's on e500v2.

The only generic modification is a change of predicates for movsi, to 
reject invalid subregs on e500v2.

Tested on powerpc-eabispe and bootstrap/tested on powerpc-linux.

Committed to mainline and 3.4-e500-branch.

Aldy

	* config/rs6000/rs6000.h (CLASS_MAX_NREGS): DF goes in 1 register
	on e500v2.
	(CANNOT_CHANGE_MODE_CLASS): Restrict DI mode changes on e500v2.
	(PREDICATE_CODES): Add rs6k_nonimmediate_operand.

	* config/rs6000/rs6000.c (invalid_e500_subreg): New.
	(rs6k_nonimmediate_operand): New.
	(rs6000_legitimate_offset_address_p): Handle DI modes on e500v2
	correctly.
	(legitimate_lo_sum_address_p): Same.
	(rs6000_legitimize_address): Same.
	(rs6000_legitimize_reload_address): Same.
	(rs6000_legitimate_address): Same.
	(spe_build_register_parallel): Pass DF and DC modes in a DI
	register.

	* config/rs6000/rs6000.md ("*movsi_internal1"): Change predicate
	to rs6k_nonimmediate_operand.

	* config/rs6000/spe.md ("*frob_df_di"): New.
	("*frob_di_df"): New.
	("*frob_di_df_2"): New.
	("*mov_sidf_e500_subreg0"): New.
	("*mov_sidf_e500_subreg4"): New.
	("*movdf_e500_double"): Change predicate to
	rs6k_nonimmediate_operand.

Index: config/rs6000/rs6000.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.350
diff -c -p -r1.350 rs6000.h
*** config/rs6000/rs6000.h	30 Dec 2004 03:08:05 -0000	1.350
--- config/rs6000/rs6000.h	14 Jan 2005 21:14:55 -0000
*************** enum reg_class
*** 1429,1434 ****
--- 1429,1436 ----
  #define CLASS_MAX_NREGS(CLASS, MODE)					\
   (((CLASS) == FLOAT_REGS) 						\
    ? ((GET_MODE_SIZE (MODE) + UNITS_PER_FP_WORD - 1) / UNITS_PER_FP_WORD) \
+   : (TARGET_E500_DOUBLE && (CLASS) == GENERAL_REGS && (MODE) == DFmode) \
+   ? 1                                                                   \
    : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
  
  
*************** enum reg_class
*** 1442,1447 ****
--- 1444,1451 ----
     ? reg_classes_intersect_p (FLOAT_REGS, CLASS)			  \
     : (TARGET_E500_DOUBLE && (((TO) == DFmode) + ((FROM) == DFmode)) == 1) \
     ? reg_classes_intersect_p (GENERAL_REGS, CLASS)			  \
+    : (TARGET_E500_DOUBLE && (((TO) == DImode) + ((FROM) == DImode)) == 1) \
+    ? reg_classes_intersect_p (GENERAL_REGS, CLASS)			  \
     : (TARGET_SPE && (SPE_VECTOR_MODE (FROM) + SPE_VECTOR_MODE (TO)) == 1) \
     ? reg_classes_intersect_p (GENERAL_REGS, CLASS)			  \
     : 0)
*************** extern char rs6000_reg_names[][8];	/* re
*** 2588,2593 ****
--- 2592,2598 ----
    {"current_file_function_operand", {SYMBOL_REF}},			   \
    {"input_operand", {SUBREG, MEM, REG, CONST_INT,			   \
  		     CONST_DOUBLE, SYMBOL_REF}},			   \
+   {"rs6k_nonimmediate_operand", {SUBREG, MEM, REG}},		   	   \
    {"load_multiple_operation", {PARALLEL}},				   \
    {"store_multiple_operation", {PARALLEL}},				   \
    {"lmw_operation", {PARALLEL}},					   \
Index: config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.777
diff -c -p -r1.777 rs6000.c
*** config/rs6000/rs6000.c	14 Jan 2005 16:51:34 -0000	1.777
--- config/rs6000/rs6000.c	14 Jan 2005 21:15:03 -0000
*************** static rtx spe_expand_builtin (tree, rtx
*** 710,715 ****
--- 710,716 ----
  static rtx spe_expand_stv_builtin (enum insn_code, tree);
  static rtx spe_expand_predicate_builtin (enum insn_code, tree, rtx);
  static rtx spe_expand_evsel_builtin (enum insn_code, tree, rtx);
+ static bool invalid_e500_subreg (rtx, enum machine_mode);
  static int rs6000_emit_int_cmove (rtx, rtx, rtx, rtx);
  static rs6000_stack_t *rs6000_stack_info (void);
  static void debug_stack_info (rs6000_stack_t *);
*************** input_operand (rtx op, enum machine_mode
*** 3035,3040 ****
--- 3036,3074 ----
    return 0;
  }
  
+ /* Return TRUE if OP is an invalid SUBREG operation on the e500.  */
+ static bool
+ invalid_e500_subreg (rtx op, enum machine_mode mode)
+ {
+   /* Reject (subreg:SI (reg:DF)).  */
+   if (GET_CODE (op) == SUBREG
+       && mode == SImode
+       && REG_P (SUBREG_REG (op))
+       && GET_MODE (SUBREG_REG (op)) == DFmode)
+     return true;
+ 
+   /* Reject (subreg:DF (reg:DI)).  */
+   if (GET_CODE (op) == SUBREG
+       && mode == DFmode
+       && REG_P (SUBREG_REG (op))
+       && GET_MODE (SUBREG_REG (op)) == DImode)
+     return true;
+ 
+   return false;
+ }
+ 
+ /* Just like nonimmediate_operand, but return 0 for invalid SUBREG's
+    on the e500.  */
+ int
+ rs6k_nonimmediate_operand (rtx op, enum machine_mode mode)
+ {
+   if (TARGET_E500_DOUBLE
+       && GET_CODE (op) == SUBREG
+       && invalid_e500_subreg (op, mode))
+     return 0;
+ 
+   return nonimmediate_operand (op, mode);
+ }
  
  /* Darwin, AIX increases natural record alignment to doubleword if the first
     field is an FP double while the FP fields remain word aligned.  */
*************** rs6000_legitimate_offset_address_p (enum
*** 3248,3253 ****
--- 3282,3295 ----
  	return SPE_CONST_OFFSET_OK (offset);
  
      case DImode:
+       /* On e500v2, we may have:
+ 
+ 	   (subreg:DF (mem:DI (plus (reg) (const_int))) 0).
+ 
+          Which gets addressed with evldd instructions.  */
+       if (TARGET_E500_DOUBLE)
+ 	return SPE_CONST_OFFSET_OK (offset);
+ 
        if (mode == DFmode || !TARGET_POWERPC64)
  	extra = 4;
        else if (offset & 3)
*************** legitimate_lo_sum_address_p (enum machin
*** 3326,3332 ****
      return false;
    if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
      return false;
!   if (TARGET_E500_DOUBLE && mode == DFmode)
      return false;
    x = XEXP (x, 1);
  
--- 3368,3375 ----
      return false;
    if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
      return false;
!   /* Restrict addressing for DI because of our SUBREG hackery.  */
!   if (TARGET_E500_DOUBLE && (mode == DFmode || mode == DImode))
      return false;
    x = XEXP (x, 1);
  
*************** rs6000_legitimize_address (rtx x, rtx ol
*** 3403,3409 ****
  	   && GET_MODE_NUNITS (mode) == 1
  	   && ((TARGET_HARD_FLOAT && TARGET_FPRS)
  	       || TARGET_POWERPC64
! 	       || ((mode != DFmode || TARGET_E500_DOUBLE) && mode != TFmode))
  	   && (TARGET_POWERPC64 || mode != DImode)
  	   && mode != TImode)
      {
--- 3446,3453 ----
  	   && GET_MODE_NUNITS (mode) == 1
  	   && ((TARGET_HARD_FLOAT && TARGET_FPRS)
  	       || TARGET_POWERPC64
! 	       || (((mode != DImode && mode != DFmode) || TARGET_E500_DOUBLE)
! 		   && mode != TFmode))
  	   && (TARGET_POWERPC64 || mode != DImode)
  	   && mode != TImode)
      {
*************** rs6000_legitimize_address (rtx x, rtx ol
*** 3423,3430 ****
        return reg;
      }
    else if (SPE_VECTOR_MODE (mode)
! 	   || (TARGET_E500_DOUBLE && mode == DFmode))
      {
        /* We accept [reg + reg] and [reg + OFFSET].  */
  
        if (GET_CODE (x) == PLUS)
--- 3467,3477 ----
        return reg;
      }
    else if (SPE_VECTOR_MODE (mode)
! 	   || (TARGET_E500_DOUBLE && (mode == DFmode
! 				      || mode == DImode)))
      {
+       if (mode == DImode)
+ 	return NULL_RTX;
        /* We accept [reg + reg] and [reg + OFFSET].  */
  
        if (GET_CODE (x) == PLUS)
*************** rs6000_legitimize_reload_address (rtx x,
*** 3834,3840 ****
        && REG_MODE_OK_FOR_BASE_P (XEXP (x, 0), mode)
        && GET_CODE (XEXP (x, 1)) == CONST_INT
        && !SPE_VECTOR_MODE (mode)
!       && !(TARGET_E500_DOUBLE && mode == DFmode)
        && !ALTIVEC_VECTOR_MODE (mode))
      {
        HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
--- 3881,3888 ----
        && REG_MODE_OK_FOR_BASE_P (XEXP (x, 0), mode)
        && GET_CODE (XEXP (x, 1)) == CONST_INT
        && !SPE_VECTOR_MODE (mode)
!       && !(TARGET_E500_DOUBLE && (mode == DFmode
! 				  || mode == DImode))
        && !ALTIVEC_VECTOR_MODE (mode))
      {
        HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
*************** rs6000_legitimate_address (enum machine_
*** 3942,3948 ****
    if ((GET_CODE (x) == PRE_INC || GET_CODE (x) == PRE_DEC)
        && !ALTIVEC_VECTOR_MODE (mode)
        && !SPE_VECTOR_MODE (mode)
!       && !(TARGET_E500_DOUBLE && mode == DFmode)
        && TARGET_UPDATE
        && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict))
      return 1;
--- 3990,3997 ----
    if ((GET_CODE (x) == PRE_INC || GET_CODE (x) == PRE_DEC)
        && !ALTIVEC_VECTOR_MODE (mode)
        && !SPE_VECTOR_MODE (mode)
!       /* Restrict addressing for DI because of our SUBREG hackery.  */
!       && !(TARGET_E500_DOUBLE && (mode == DFmode || mode == DImode))
        && TARGET_UPDATE
        && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict))
      return 1;
*************** function_arg_advance (CUMULATIVE_ARGS *c
*** 5084,5114 ****
  static rtx
  spe_build_register_parallel (enum machine_mode mode, int gregno)
  {
!   rtx r1, r2, r3, r4;
!   enum machine_mode inner = SImode;
  
    if (mode == DFmode)
      {
!       r1 = gen_rtx_REG (inner, gregno);
!       r1 = gen_rtx_EXPR_LIST (SImode, r1, const0_rtx);
!       r2 = gen_rtx_REG (inner, gregno + 1);
!       r2 = gen_rtx_EXPR_LIST (SImode, r2, GEN_INT (4));
!       return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
      }
    else if (mode == DCmode)
      {
!       r1 = gen_rtx_REG (inner, gregno);
!       r1 = gen_rtx_EXPR_LIST (SImode, r1, const0_rtx);
!       r2 = gen_rtx_REG (inner, gregno + 1);
!       r2 = gen_rtx_EXPR_LIST (SImode, r2, GEN_INT (4));
!       r3 = gen_rtx_REG (inner, gregno + 2);
!       r3 = gen_rtx_EXPR_LIST (SImode, r3, GEN_INT (8));
!       r4 = gen_rtx_REG (inner, gregno + 3);
!       r4 = gen_rtx_EXPR_LIST (SImode, r4, GEN_INT (12));
!       return gen_rtx_PARALLEL (mode, gen_rtvec (4, r1, r2, r3, r4));
      }
! 
!   abort ();
    return NULL_RTX;
  }
  
--- 5133,5155 ----
  static rtx
  spe_build_register_parallel (enum machine_mode mode, int gregno)
  {
!   rtx r1, r3;
  
    if (mode == DFmode)
      {
!       r1 = gen_rtx_REG (DImode, gregno);
!       r1 = gen_rtx_EXPR_LIST (VOIDmode, r1, const0_rtx);
!       return gen_rtx_PARALLEL (mode, gen_rtvec (1, r1));
      }
    else if (mode == DCmode)
      {
!       r1 = gen_rtx_REG (DImode, gregno);
!       r1 = gen_rtx_EXPR_LIST (VOIDmode, r1, const0_rtx);
!       r3 = gen_rtx_REG (DImode, gregno + 2);
!       r3 = gen_rtx_EXPR_LIST (VOIDmode, r3, GEN_INT (8));
!       return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r3));
      }
!   abort();
    return NULL_RTX;
  }
  
Index: config/rs6000/rs6000.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.md,v
retrieving revision 1.340
diff -c -p -r1.340 rs6000.md
*** config/rs6000/rs6000.md	12 Jan 2005 12:22:25 -0000	1.340
--- config/rs6000/rs6000.md	14 Jan 2005 21:15:07 -0000
***************
*** 7709,7715 ****
     (set_attr "length" "4")])
  
  (define_insn "*movsi_internal1"
!   [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,m,r,r,r,r,r,*q,*c*l,*h,*h")
  	(match_operand:SI 1 "input_operand" "r,U,m,r,I,L,n,R,*h,r,r,r,0"))]
    "gpc_reg_operand (operands[0], SImode)
     || gpc_reg_operand (operands[1], SImode)"
--- 7709,7715 ----
     (set_attr "length" "4")])
  
  (define_insn "*movsi_internal1"
!   [(set (match_operand:SI 0 "rs6k_nonimmediate_operand" "=r,r,r,m,r,r,r,r,r,*q,*c*l,*h,*h")
  	(match_operand:SI 1 "input_operand" "r,U,m,r,I,L,n,R,*h,r,r,r,0"))]
    "gpc_reg_operand (operands[0], SImode)
     || gpc_reg_operand (operands[1], SImode)"
Index: config/rs6000/spe.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/spe.md,v
retrieving revision 1.29
diff -c -p -r1.29 spe.md
*** config/rs6000/spe.md	10 Nov 2004 01:08:22 -0000	1.29
--- config/rs6000/spe.md	14 Jan 2005 21:15:08 -0000
***************
*** 2192,2199 ****
     (set_attr  "length" "4")])
  
  ;; Double-precision floating point instructions.
  (define_insn "*movdf_e500_double"
!   [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m")
  	(match_operand:DF 1 "input_operand" "r,m,r"))]
    "TARGET_HARD_FLOAT && TARGET_E500_DOUBLE
      && (gpc_reg_operand (operands[0], DFmode)
--- 2192,2236 ----
     (set_attr  "length" "4")])
  
  ;; Double-precision floating point instructions.
+ 
+ ;; FIXME: Add o=r option.
+ (define_insn "*frob_df_di"
+   [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r")
+         (subreg:DF (match_operand:DI 1 "input_operand" "r,m") 0))]
+   "TARGET_E500_DOUBLE"
+   "@
+    evmergelo %0,%H1,%L1
+    evldd%X1 %0,%y1")
+ 
+ (define_insn "*frob_di_df"
+   [(set (match_operand:DI 0 "nonimmediate_operand" "=&r")
+         (subreg:DI (match_operand:DF 1 "input_operand" "r") 0))]
+   "TARGET_E500_DOUBLE" /*one of these can be an mr */
+   "evmergehi %H0,%1,%1\;evmergelo %L0,%1,%1"
+   [(set_attr "length" "8")])
+ 
+ (define_insn "*frob_di_df_2"
+   [(set (subreg:DF (match_operand:DI 0 "register_operand" "=&r") 0)
+ 	(match_operand:DF 1 "register_operand" "r"))]
+   "TARGET_E500_DOUBLE"
+   "evmergehi %H0,%1,%1\;evmergelo %L0,%1,%1"
+   [(set_attr "length" "8")])
+ 
+ (define_insn "*mov_sidf_e500_subreg0"
+   [(set (subreg:SI (match_operand:DF 0 "register_operand" "+r") 0)
+ 	(match_operand:SI 1 "register_operand" "r"))]
+   "TARGET_E500_DOUBLE"
+   "evmergelo %0,%1,%0")
+ 
+ (define_insn "*mov_sidf_e500_subreg4"
+   [(set (subreg:SI (match_operand:DF 0 "register_operand" "+r") 4)
+ 	(match_operand:SI 1 "register_operand" "r"))]
+   "TARGET_E500_DOUBLE"
+   "mr %0,%1")
+ 
+ ;; FIXME: Allow r=CONST0.
  (define_insn "*movdf_e500_double"
!   [(set (match_operand:DF 0 "rs6k_nonimmediate_operand" "=r,r,m")
  	(match_operand:DF 1 "input_operand" "r,m,r"))]
    "TARGET_HARD_FLOAT && TARGET_E500_DOUBLE
      && (gpc_reg_operand (operands[0], DFmode)


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