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 RFC] SH: Use FRAME_GROWS_DOWNWARD


Kaz Kojima wrote:



patch. The tweaked testcase in
http://gcc.gnu.org/ml/gcc-patches/2005-07/msg01282.html
passes for sh-elf but fails for sh-elf/-m4. The assembler output


The insns emitted by untyped_call are too imprecise about the register
lifeness.  Another problem is that TImode floating point moves can't
actually be generated for little endian, and we need an untyped_return
pattern in order to make the __builtin_return safe for mode switching.

I've also found a type in HARD_REGNO_MODE_OK.

2005-07-21  J"orn Rennecke <joern.rennecke@st.com>

	* builtins.c (apply_result_size): Consider modes that span multiple
	hard registers.

	* sh.md (UNSPEC_CALL_RESULT): New constant.
	(movti, untyped_call_result, untyped_return): New patterns.
	(untyped_call): Prune modes to maximum that actually appear in return
	types.  Use untyped_call_result.  Save general purpose registers first.

	* sh.h (HARDREG_REGNO_NREGS): Fix DCmode handling in floating point
	registers.

Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.450.2.2
diff -p -r1.450.2.2 builtins.c
*** builtins.c	19 Jul 2005 15:43:00 -0000	1.450.2.2
--- builtins.c	21 Jul 2005 20:09:06 -0000
*************** apply_result_size (void)
*** 1119,1128 ****
--- 1119,1140 ----
        for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
  	if (FUNCTION_VALUE_REGNO_P (regno))
  	  {
+ 	    unsigned n;
+ 	    enum machine_mode wider_mode;
+ 
  	    mode = reg_raw_mode[regno];
  
  	    gcc_assert (mode != VOIDmode);
  
+ 	    n = hard_regno_nregs[regno][mode];
+ 	    while (regno + n < FIRST_PSEUDO_REGISTER
+ 		   && call_used_regs[regno + n])
+ 	      {
+ 		n++;
+ 		wider_mode = choose_hard_reg_mode (regno, n, false);
+ 		if (wider_mode != VOIDmode)
+ 		  mode = wider_mode;
+ 	      }
  	    align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
  	    if (size % align != 0)
  	      size = CEIL (size, align) * align;
Index: config/sh/sh.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sh/sh.h,v
retrieving revision 1.262.2.7
diff -p -r1.262.2.7 sh.h
*** config/sh/sh.h	20 Jul 2005 03:18:15 -0000	1.262.2.7
--- config/sh/sh.h	21 Jul 2005 20:10:36 -0000
*************** extern char sh_additional_register_names
*** 1160,1168 ****
     : FP_REGISTER_P (REGNO) \
     ? ((MODE) == SFmode || (MODE) == SImode \
        || ((TARGET_SH2E || TARGET_SHMEDIA) && (MODE) == SCmode) \
!       || ((((TARGET_SH4 || TARGET_SH2A_DOUBLE) && (MODE) == DFmode) || (MODE) == DCmode \
! 	   || (TARGET_SHMEDIA && ((MODE) == DFmode || (MODE) == DImode \
! 				  || (MODE) == V2SFmode || (MODE) == TImode))) \
  	  && (((REGNO) - FIRST_FP_REG) & 1) == 0) \
        || ((TARGET_SH4 || TARGET_SHMEDIA) \
  	  && (MODE) == TImode \
--- 1160,1170 ----
     : FP_REGISTER_P (REGNO) \
     ? ((MODE) == SFmode || (MODE) == SImode \
        || ((TARGET_SH2E || TARGET_SHMEDIA) && (MODE) == SCmode) \
!       || ((((TARGET_SH4 || TARGET_SH2A_DOUBLE) \
! 	    && ((MODE) == DFmode) || (MODE) == DCmode) \
! 	   || (TARGET_SHMEDIA \
! 	       && ((MODE) == DFmode || (MODE) == DCmode || (MODE) == DImode \
! 		   || (MODE) == V2SFmode || (MODE) == TImode))) \
  	  && (((REGNO) - FIRST_FP_REG) & 1) == 0) \
        || ((TARGET_SH4 || TARGET_SHMEDIA) \
  	  && (MODE) == TImode \
Index: config/sh/sh.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sh/sh.md,v
retrieving revision 1.191.2.4
diff -p -F^( -r1.191.2.4 sh.md
*** config/sh/sh.md	20 Jul 2005 22:14:03 -0000	1.191.2.4
--- config/sh/sh.md	21 Jul 2005 20:14:49 -0000
*************** (define_constants [
*** 150,155 ****
--- 150,156 ----
    (UNSPEC_DIV_INV20	34)
    (UNSPEC_ASHIFTRT	35)
    (UNSPEC_THUNK		36)
+   (UNSPEC_CALL_RESULT	37)
    (UNSPEC_SP_SET	40)
    (UNSPEC_SP_TEST	41)
  
*************** (define_expand "movdi"
*** 5591,5596 ****
--- 5592,5623 ----
    ""
    "{ if (prepare_move_operands (operands, DImode)) DONE; }")
  
+ (define_expand "movti"
+   [(set (match_operand:TI 0 "general_movdst_operand" "")
+ 	(match_operand:TI 1 "general_movsrc_operand" ""))]
+   "TARGET_FPU_DOUBLE"
+   "
+ {
+   rtx high_src, high_dst;
+   enum machine_mode part_mode = DImode;
+ 
+   if ((REG_P (operands[0]) && FP_REGISTER_P (REGNO (operands[0])))
+       || (REG_P (operands[1]) && FP_REGISTER_P (REGNO (operands[1]))))
+     part_mode = DFmode;
+   emit_move_insn (gen_lowpart (part_mode, operands[0]),
+ 		  gen_lowpart (part_mode, operands[1]));
+   high_src = simplify_gen_subreg (part_mode, operands[1], TImode,
+ 				  TARGET_LITTLE_ENDIAN ? 8 : 0);
+   if (MEM_P (high_src))
+     high_src = validize_mem (high_src);
+   high_dst = simplify_gen_subreg (part_mode, operands[0], TImode,
+ 				  TARGET_LITTLE_ENDIAN ? 8 : 0);
+   if (MEM_P (high_dst))
+     high_dst = validize_mem (high_dst);
+   emit_move_insn (high_dst, high_src);
+   DONE;
+ }")
+ 
  (define_insn "movdf_media"
    [(set (match_operand:DF 0 "general_movdst_operand" "=f,f,r,r,r,f,m,r,m")
  	(match_operand:DF 1 "general_movsrc_operand" "f,rZ,f,r,F,m,f,m,rZ"))]
*************** (define_expand "untyped_call"
*** 8075,8101 ****
  		    (const_int 0))
  	      (match_operand 1 "" "")
  	      (match_operand 2 "" "")])]
!   "(TARGET_SH2E || TARGET_SH2A) || TARGET_SHMEDIA"
    "
  {
    int i;
! 
!   emit_call_insn (gen_call (operands[0], const0_rtx, const0_rtx));
! 
    for (i = 0; i < XVECLEN (operands[2], 0); i++)
      {
        rtx set = XVECEXP (operands[2], 0, i);
!       emit_move_insn (SET_DEST (set), SET_SRC (set));
!     }
  
    /* The optimizer does not know that the call sets the function value
!      registers we stored in the result block.  We avoid problems by
!      claiming that all hard registers are used and clobbered at this
!      point.  */
!   emit_insn (gen_blockage ());
  
    DONE;
  }")
  
  ;; ------------------------------------------------------------------------
  ;; Misc insns
--- 8102,8221 ----
  		    (const_int 0))
  	      (match_operand 1 "" "")
  	      (match_operand 2 "" "")])]
!   ""
    "
  {
    int i;
!   /* result[0] is for genereal purpose registers, result[1] for floating
!      point.  reg is the register that holds the result, insn copies it to
!      memory.  */
!   struct { rtx reg, insn; } result[2];
! 
!   emit_call_insn (gen_call_value (gen_rtx_REG (TImode, R0_REG),
! 				  operands[0], const0_rtx, const0_rtx));
!   result[1].reg = gen_rtx_REG (SImode, PR_REG);
!   result[1].insn = NULL_RTX;
    for (i = 0; i < XVECLEN (operands[2], 0); i++)
      {
        rtx set = XVECEXP (operands[2], 0, i);
!       rtx src = SET_SRC (set);
!       rtx dst = SET_DEST (set);
!       int fp = 0;
!       enum machine_mode mode;
  
+       gcc_assert (REG_P (src));
+       switch (REGNO (src))
+ 	{
+ 	case R0_REG:
+ 	  mode = CDImode;
+ 	  break;
+ 	case R2_REG:
+ 	  mode = DImode;
+ 	  break;
+ 	case DR0_REG:
+ 	  mode = TARGET_SH5 ? DFmode : TARGET_FPU_DOUBLE ? DCmode : SCmode;
+ 	  fp = 1;
+ 	  break;
+ 	default:
+ 	  gcc_unreachable ();
+ 	}
+       result[fp].reg = src = gen_rtx_REG (mode, REGNO (src));
+       dst = change_address (dst, mode, NULL);
+       result[fp].insn = gen_move_insn (dst, src);
+     }
    /* The optimizer does not know that the call sets the function value
!      registers we'll store in the result block.  */
! 
!   emit_insn (gen_untyped_call_result(result[0].reg, result[1].reg));
!   emit_insn (result[0].insn);
!   if (result[1].insn)
!     emit_insn (result[1].insn);
!   DONE;
! }")
! 
! (define_insn "untyped_call_result"
!   [(set (match_operand:CDI 0 "register_operand" "=r")
! 	(unspec:CDI [(reg:TI R0_REG)] UNSPEC_CALL_RESULT))
!    (set (match_operand 1 "" "=fl")
! 	(unspec [(reg:DC R0_REG) (match_dup 1)] UNSPEC_CALL_RESULT))]
!   ""
!   ""
!   [(set_attr "length" "0")])
! 
! (define_expand "untyped_return"
!   [(match_operand:BLK 0 "memory_operand" "")
!    (match_operand 1 "" "")]
!   "TARGET_SH4 || TARGET_SH2A_DOUBLE"
!   "
! {
!   int i;
!   /* result[0] is for genereal purpose registers, result[1] for floating
!      point.  reg is the register that holds the result, insn copies it from
!      memory.  */
!   struct { rtx reg, insn; } result[2];
! 
!   result[1].reg = NULL_RTX;
!   result[1].insn = NULL_RTX;
!   for (i = 0; i < XVECLEN (operands[1], 0); i++)
!     {
!       rtx set = XVECEXP (operands[1], 0, i);
!       rtx src = SET_SRC (set);
!       rtx dst = SET_DEST (set);
!       int fp = 0;
!       enum machine_mode mode;
  
+       gcc_assert (REG_P (dst));
+       switch (REGNO (dst))
+ 	{
+ 	case R0_REG:
+ 	  mode = CDImode;
+ 	  break;
+ 	case R2_REG:
+ 	  mode = DImode;
+ 	  break;
+ 	case DR0_REG:
+ 	  mode = TARGET_SH5 ? DFmode : TARGET_FPU_DOUBLE ? DCmode : SCmode;
+ 	  fp = 1;
+ 	  break;
+ 	default:
+ 	  gcc_unreachable ();
+ 	}
+       result[fp].reg = dst = gen_rtx_REG (mode, REGNO (dst));
+       src = change_address (src, mode, NULL);
+       result[fp].insn = gen_move_insn (dst, src);
+     }
+   /* Because of the register requirements of mode switching, we must first
+      load the floating point result registers, and then the general purpose
+      result registers.  */
+   if (result[1].insn)
+     emit_insn (result[1].insn);
+   emit_insn (result[0].insn);
+   emit_insn (gen_rtx_USE (VOIDmode, result[1].reg));
+   emit_insn (gen_rtx_USE (VOIDmode, result[0].reg));
+   expand_naked_return ();
    DONE;
  }")
+ 
  
  ;; ------------------------------------------------------------------------
  ;; Misc insns

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