From 7a61cf6f09d0a08de70d1f15f089a79cbec1ab1e Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Mon, 6 Jul 2009 13:55:09 +0000 Subject: lib1funcs.h (FMOVD_WORKS): Only define if __FMOVD_ENABLED__ is defined. * config.sh/lib1funcs.h (FMOVD_WORKS): Only define if __FMOVD_ENABLED__ is defined. * config/sh/sh.h (TARGET_FMOVD): Provide a default definition. (MASK_FMOVD): Likewise. (TARGET_CPU_CPP_BUILTINS): Define __FMOVD_ENABLED__ if TARGET_FMOVD is true. * config/sh/sh.md (movdf_i4): For alternative 0 use either one or two fmov instructions depending upon whether TARGET_FMOVD is enabled. (split for DF load from memory into register): Also handle MEMs which consist of REG+DISP addressing. (split for DF store from register to memory): Likewise. (movsf_ie): Always use single fp_mode. * config/sh/sh.c (sh_override_options): Do not automatically enable TARGET_MOVD for the SH2A when supporting doubles - leave that to the -mfmovd command line switch. (broken_move): Do not restrict fldi test to only the SH4 and SH4A. (fldi_ok): Always allow. * config/sh/sh.opt (mfmovd): Remove this switch. * doc/invoke.texi (-mfmovd): Remove documentation of this switch. Co-Authored-By: DJ Delorie From-SVN: r149283 --- gcc/config/sh/lib1funcs.h | 4 +- gcc/config/sh/sh.c | 15 ++-- gcc/config/sh/sh.h | 7 ++ gcc/config/sh/sh.md | 185 +++++++++++++++++++++++++++++++--------------- gcc/config/sh/sh.opt | 3 - 5 files changed, 140 insertions(+), 74 deletions(-) (limited to 'gcc/config/sh') diff --git a/gcc/config/sh/lib1funcs.h b/gcc/config/sh/lib1funcs.h index d16a18b..af4b41c 100644 --- a/gcc/config/sh/lib1funcs.h +++ b/gcc/config/sh/lib1funcs.h @@ -42,8 +42,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define ALIAS(X,Y) .global GLOBAL(X); .set GLOBAL(X),GLOBAL(Y) -#ifdef __SH2A__ -#undef FMOVD_WORKS +#if defined __SH2A__ && defined __FMOVD_ENABLED__ +#undef FMOVD_WORKS #define FMOVD_WORKS #endif diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 08cae31..18123c3 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -694,11 +694,7 @@ sh_override_options (void) if (TARGET_SH2E) sh_cpu = PROCESSOR_SH2E; if (TARGET_SH2A) - { - sh_cpu = PROCESSOR_SH2A; - if (TARGET_SH2A_DOUBLE) - target_flags |= MASK_FMOVD; - } + sh_cpu = PROCESSOR_SH2A; if (TARGET_SH3) sh_cpu = PROCESSOR_SH3; if (TARGET_SH3E) @@ -4208,14 +4204,13 @@ broken_move (rtx insn) && GET_CODE (SET_SRC (pat)) == CONST_DOUBLE && (fp_zero_operand (SET_SRC (pat)) || fp_one_operand (SET_SRC (pat))) - /* ??? If this is a -m4 or -m4-single compilation, in general - we don't know the current setting of fpscr, so disable fldi. + /* In general we don't know the current setting of fpscr, so disable fldi. There is an exception if this was a register-register move before reload - and hence it was ascertained that we have single precision setting - and in a post-reload optimization we changed this to do a constant load. In that case we don't have an r0 clobber, hence we must use fldi. */ - && (! TARGET_SH4 || TARGET_FMOVD + && (TARGET_FMOVD || (GET_CODE (XEXP (XVECEXP (PATTERN (insn), 0, 2), 0)) == SCRATCH)) && REG_P (SET_DEST (pat)) @@ -8876,7 +8871,7 @@ fp_one_operand (rtx op) return REAL_VALUES_EQUAL (r, dconst1); } -/* For -m4 and -m4-single-only, mode switching is used. If we are +/* In general mode switching is used. If we are compiling without -mfmovd, movsf_ie isn't taken into account for mode switching. We could check in machine_dependent_reorg for cases where we know we are in single precision mode, but there is @@ -8886,7 +8881,7 @@ fp_one_operand (rtx op) int fldi_ok (void) { - return ! TARGET_SH4 || TARGET_FMOVD || reload_completed; + return 1; } int diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h index d8b9a29..d9a4c5f 100644 --- a/gcc/config/sh/sh.h +++ b/gcc/config/sh/sh.h @@ -28,6 +28,11 @@ along with GCC; see the file COPYING3. If not see #define TARGET_VERSION \ fputs (" (Hitachi SH)", stderr); +#ifndef TARGET_FMOVD +#define TARGET_FMOVD 0 +#define MASK_FMOVD 0 +#endif + /* Unfortunately, insn-attrtab.c doesn't include insn-codes.h. We can't include it here, because bconfig.h is also included by gencodes.c . */ /* ??? No longer true. */ @@ -91,6 +96,8 @@ do { \ builtin_define ("__SH_FPU_DOUBLE__"); \ if (TARGET_HITACHI) \ builtin_define ("__HITACHI__"); \ + if (TARGET_FMOVD) \ + builtin_define ("__FMOVD_ENABLED__"); \ builtin_define (TARGET_LITTLE_ENDIAN \ ? "__LITTLE_ENDIAN__" : "__BIG_ENDIAN__"); \ } while (0) diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index e446164..30084c2 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -5780,25 +5780,31 @@ label: ;; up pcloads, so we need usable length information for that. (define_insn "movdf_i4" [(set (match_operand:DF 0 "general_movdst_operand" "=d,r,d,d,m,r,r,m,!??r,!???d") - (match_operand:DF 1 "general_movsrc_operand" "d,r,F,m,d,FQ,m,r,d,r")) - (use (match_operand:PSI 2 "fpscr_operand" "c,c,c,c,c,c,c,c,c,c")) - (clobber (match_scratch:SI 3 "=X,X,&z,X,X,X,X,X,X,X"))] + (match_operand:DF 1 "general_movsrc_operand" "d,r,F,m,d,FQ,m,r,d,r")) + (use (match_operand:PSI 2 "fpscr_operand" "c,c,c,c,c,c,c,c,c,c")) + (clobber (match_scratch:SI 3 "=X,X,&z,X,X,X,X,X,X,X"))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE) && (arith_reg_operand (operands[0], DFmode) || arith_reg_operand (operands[1], DFmode))" - "@ - fmov %1,%0 - # - # - fmov.d %1,%0 - fmov.d %1,%0 - # - # - # - # - #" + { + switch (which_alternative) + { + case 0: + if (TARGET_FMOVD) + return "fmov %1,%0"; + else if (REGNO (operands[0]) != REGNO (operands[1]) + 1) + return "fmov %R1,%R0\n\tfmov %S1,%S0"; + else + return "fmov %S1,%S0\n\tfmov %R1,%R0"; + case 3: + case 4: + return "fmov.d %1,%0"; + default: + return "#"; + } + } [(set_attr_alternative "length" - [(if_then_else (eq_attr "fmovd" "yes") (const_int 2) (const_int 4)) + [(if_then_else (eq_attr "fmovd" "yes") (const_int 4) (const_int 8)) (const_int 4) (if_then_else (eq_attr "fmovd" "yes") (const_int 4) (const_int 6)) (if_then_else (eq_attr "fmovd" "yes") (const_int 4) (const_int 6)) @@ -6032,37 +6038,63 @@ label: "(TARGET_SH4 || TARGET_SH2A_DOUBLE) && ! TARGET_FMOVD && reload_completed && FP_OR_XD_REGISTER_P (true_regnum (operands[0]))" [(const_int 0)] - " { int regno = true_regnum (operands[0]); - rtx addr, insn, adjust = NULL_RTX; + rtx addr, insn; rtx mem2 = change_address (operands[1], SFmode, NULL_RTX); - rtx reg0 = gen_rtx_REG (SFmode, regno + !! TARGET_LITTLE_ENDIAN); - rtx reg1 = gen_rtx_REG (SFmode, regno + ! TARGET_LITTLE_ENDIAN); + rtx reg0 = gen_rtx_REG (SFmode, regno + (TARGET_LITTLE_ENDIAN ? 1 : 0)); + rtx reg1 = gen_rtx_REG (SFmode, regno + (TARGET_LITTLE_ENDIAN ? 0 : 1)); operands[1] = copy_rtx (mem2); addr = XEXP (mem2, 0); - if (GET_CODE (addr) != POST_INC) + + switch (GET_CODE (addr)) { - /* If we have to modify the stack pointer, the value that we have - read with post-increment might be modified by an interrupt, - so write it back. */ - if (REGNO (addr) == STACK_POINTER_REGNUM) - adjust = gen_push_e (reg0); - else - adjust = gen_addsi3 (addr, addr, GEN_INT (-4)); - XEXP (mem2, 0) = addr = gen_rtx_POST_INC (SImode, addr); - } - addr = XEXP (addr, 0); - insn = emit_insn (gen_movsf_ie (reg0, mem2, operands[2])); - add_reg_note (insn, REG_INC, addr); - insn = emit_insn (gen_movsf_ie (reg1, operands[1], operands[2])); - if (adjust) - emit_insn (adjust); - else - add_reg_note (insn, REG_INC, addr); + case REG: + /* This is complicated. If the register is an arithmetic register + we can just fall through to the REG+DISP case below. Otherwise + we have to use a combination of POST_INC and REG addressing... */ + if (! arith_reg_operand (operands[1], SFmode)) + { + XEXP (mem2, 0) = addr = gen_rtx_POST_INC (SImode, addr); + insn = emit_insn (gen_movsf_ie (reg0, mem2, operands[2])); + add_reg_note (insn, REG_INC, XEXP (addr, 0)); + + emit_insn (gen_movsf_ie (reg1, operands[1], operands[2])); + + /* If we have modified the stack pointer, the value that we have + read with post-increment might be modified by an interrupt, + so write it back. */ + if (REGNO (addr) == STACK_POINTER_REGNUM) + emit_insn (gen_push_e (reg0)); + else + emit_insn (gen_addsi3 (XEXP (operands[1], 0), XEXP (operands[1], 0), GEN_INT (-4))); + break; + } + /* Fall through. */ + + case PLUS: + emit_insn (gen_movsf_ie (reg0, operands[1], operands[2])); + operands[1] = copy_rtx (operands[1]); + XEXP (operands[1], 0) = plus_constant (addr, 4); + emit_insn (gen_movsf_ie (reg1, operands[1], operands[2])); + break; + + case POST_INC: + insn = emit_insn (gen_movsf_ie (reg0, operands[1], operands[2])); + add_reg_note (insn, REG_INC, XEXP (addr, 0)); + + insn = emit_insn (gen_movsf_ie (reg1, operands[1], operands[2])); + add_reg_note (insn, REG_INC, XEXP (addr, 0)); + break; + + default: + debug_rtx (addr); + gcc_unreachable (); + } + DONE; -}") +}) (define_split [(set (match_operand:DF 0 "memory_operand" "") @@ -6072,35 +6104,70 @@ label: "(TARGET_SH4 || TARGET_SH2A_DOUBLE) && ! TARGET_FMOVD && reload_completed && FP_OR_XD_REGISTER_P (true_regnum (operands[1]))" [(const_int 0)] - " { int regno = true_regnum (operands[1]); - rtx insn, addr, adjust = NULL_RTX; + rtx insn, addr; + rtx reg0 = gen_rtx_REG (SFmode, regno + (TARGET_LITTLE_ENDIAN ? 1 : 0)); + rtx reg1 = gen_rtx_REG (SFmode, regno + (TARGET_LITTLE_ENDIAN ? 0 : 1)); operands[0] = copy_rtx (operands[0]); PUT_MODE (operands[0], SFmode); - insn = emit_insn (gen_movsf_ie (operands[0], - gen_rtx_REG (SFmode, - regno + ! TARGET_LITTLE_ENDIAN), - operands[2])); - operands[0] = copy_rtx (operands[0]); addr = XEXP (operands[0], 0); - if (GET_CODE (addr) != PRE_DEC) + + switch (GET_CODE (addr)) { - adjust = gen_addsi3 (addr, addr, GEN_INT (4)); - emit_insn_before (adjust, insn); - XEXP (operands[0], 0) = addr = gen_rtx_PRE_DEC (SImode, addr); + case REG: + /* This is complicated. If the register is an arithmetic register + we can just fall through to the REG+DISP case below. Otherwise + we have to use a combination of REG and PRE_DEC addressing... */ + if (! arith_reg_operand (operands[0], SFmode)) + { + emit_insn (gen_addsi3 (addr, addr, GEN_INT (4))); + emit_insn (gen_movsf_ie (operands[0], reg1, operands[2])); + + operands[0] = copy_rtx (operands[0]); + XEXP (operands[0], 0) = addr = gen_rtx_PRE_DEC (SImode, addr); + + insn = emit_insn (gen_movsf_ie (operands[0], reg0, operands[2])); + add_reg_note (insn, REG_INC, XEXP (addr, 0)); + break; + } + /* Fall through. */ + + case PLUS: + /* Since REG+DISP addressing has already been decided upon by gcc + we can rely upon it having chosen an arithmetic register as the + register component of the address. Just emit the lower numbered + register first, to the lower address, then the higher numbered + register to the higher address. */ + emit_insn (gen_movsf_ie (operands[0], reg0, operands[2])); + + operands[0] = copy_rtx (operands[0]); + XEXP (operands[0], 0) = plus_constant (addr, 4); + + emit_insn (gen_movsf_ie (operands[0], reg1, operands[2])); + break; + + case PRE_DEC: + /* This is easy. Output the word to go to the higher address + first (ie the word in the higher numbered register) then the + word to go to the lower address. */ + + insn = emit_insn (gen_movsf_ie (operands[0], reg1, operands[2])); + add_reg_note (insn, REG_INC, XEXP (addr, 0)); + + insn = emit_insn (gen_movsf_ie (operands[0], reg0, operands[2])); + add_reg_note (insn, REG_INC, XEXP (addr, 0)); + break; + + default: + /* FAIL; */ + debug_rtx (addr); + gcc_unreachable (); } - addr = XEXP (addr, 0); - if (! adjust) - add_reg_note (insn, REG_INC, addr); - insn = emit_insn (gen_movsf_ie (operands[0], - gen_rtx_REG (SFmode, - regno + !! TARGET_LITTLE_ENDIAN), - operands[2])); - add_reg_note (insn, REG_INC, addr); + DONE; -}") +}) ;; If the output is a register and the input is memory or a register, we have ;; to be careful and see which word needs to be loaded first. @@ -6562,7 +6629,7 @@ label: (const_int 0)]) (set (attr "fp_mode") (if_then_else (eq_attr "fmovd" "yes") (const_string "single") - (const_string "none")))]) + (const_string "single")))]) (define_split [(set (match_operand:SF 0 "register_operand" "") diff --git a/gcc/config/sh/sh.opt b/gcc/config/sh/sh.opt index f365b2b..b2e7c6d 100644 --- a/gcc/config/sh/sh.opt +++ b/gcc/config/sh/sh.opt @@ -248,9 +248,6 @@ mfixed-range= Target RejectNegative Joined Var(sh_fixed_range_str) Specify range of registers to make fixed -mfmovd -Target RejectNegative Mask(FMOVD) Undocumented - mfused-madd Target Var(TARGET_FMAC) Enable the use of the fused floating point multiply-accumulate operation -- cgit v1.1