This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
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