https://gcc.gnu.org/g:3c12f578a9301f108b458f5c6cef50a7568fc39f
commit r17-5310-g3c12f578a9301f108b458f5c6cef50a7568fc39f Author: Max Filippov <[email protected]> Date: Thu Aug 27 03:15:42 2026 -0700 gcc: xtensa: add DFPU support gcc/ * config/xtensa/constraints.md (Gc): Update comment and drop _S from TARGET_HARD_FLOAT_CONST. * config/xtensa/xtensa-protos.h (xtensa_expand_conditional_move): Change second argument type to machine_mode. * config/xtensa/xtensa.cc (xtensa_class_max_nregs): New function. (TARGET_CLASS_MAX_NREGS): Define new macro. (gen_float_relational): Generate DF mode comparisons in addition to SF. (xtensa_expand_conditional_branch): Change TARGET_HARD_FLOAT to TARGET_FLOAT32 under the E_SFmode case. Add gen_float_relational() call under the E_DFmode case. (gen_conditional_move): Handle DFmode case. (xtensa_expand_conditional_move): Change second argument type to machine_mode. Change if/else check for floating point/integer move to a switch for integer/single precision/double precision floating point move. (xtensa_copy_incoming_a7): Separate E_DImode and E_DFmode code and handle E_DFmode case by emitting gen_movdf_internal. (xtensa_emit_movcc): Generate conditional moves for DFmode. Use .s suffix, because .d is not handled by the assembler and both .s and .d instructions have the same encoding. (xtensa_option_override): Initialize xtensa_hard_regno_mode_ok_p for DFmode. (print_operand): Add support for 'T' and 'B' codes. Expand 'U', 'V' and 'G' conditions to cover DFmode. (xtensa_rtx_costs): Change TARGET_HARD_FLOAT to TARGET_FLOAT32. Define costs for FP operations on DF mode values when TARGET_FLOAT64 is on. (xtensa_legitimate_constant_p): Cover DF mode case. Return true for 0 and FP constants supported by const.d instruction when TARGET_FLOAT64 is on. (xtensa_zero_call_used_regs): Change TARGET_HARD_FLOAT to TARGET_FLOAT32. Handle double precision FPU registers by emitting gen_movdf_concat. (FPreg_neg_scaled_simm12b): Change TARGET_HARD_FLOAT to TARGET_FLOAT32. * config/xtensa/xtensa.h (TARGET_HARD_FLOAT): Change to to be on when either single precision or double precision hardware FP support is present. (TARGET_FLOAT32): Define to 1 when single precision FPU is available, 0 otherwise. (TARGET_FLOAT64): Define to 1 when double precision FPU is available, 0 otherwise. (TARGET_HARD_FLOAT_DIV): Rename to TARGET_FLOAT32_DIV. (TARGET_HARD_FLOAT_RECIP): Rename to TARGET_FLOAT32_RECIP. (TARGET_HARD_FLOAT_SQRT): Rename to TARGET_FLOAT32_SQRT. (TARGET_HARD_FLOAT_RSQRT): Rename to TARGET_FLOAT32_RSQRT. (TARGET_FLOAT64_DIV, TARGET_FLOAT64_RECIP, TARGET_FLOAT64_SQRT) (TARGET_FLOAT64_RSQRT): Define similarly to TARGET_FLOAT32_*, but for double precision FPU. (TARGET_HARD_FLOAT_CONST_S): Rename to TARGET_HARD_FLOAT_CONST and include 64-bit instruction variants into the condition. (UNITS_PER_FPREG): Define as 8 when 64-bit FPU is available, 4 otherwise. * config/xtensa/xtensa.md (UNSPEC_CONCAT): New unspec constant. (SDF): New mode iterator for SF and DF. (sd, sdf_mode_bits): New mode attributes. (addsf3, subsf3, mulsf3, fmasf4, fnmasf4, abssf2, negsf2) (fix<s_fix>_truncsfsi2, *fix<s_fix>_truncsfsi2_2x) (*fix<s_fix>_truncsfsi2_scaled, float<s_float>sisf2) (*float<s_float>sisf2_scaled, l<m_round>sfsi2) (*l<m_round>sfsi2_2x, *l<m_round>sfsi2_scaled, *lsip, *ssip) (cbranchsf4, cstoresf4, movsfcc, movsfcc_internal0) (movsfcc_internal1, s<code>_sf): Extend support to DF mode using SDF iterator and corresponding attributes. (extendsfdf2, truncdfsf2, movdf_concat): New patterns. (movdf): Don't force second argument to a memory const if it satisfies the Gc constraint. (movdf_internal): Add instructions for arguments matching the f constraint. Don't do the split if either argument is in the hard FP register. gcc/testsuite/ * gcc.target/xtensa/constsynthV2_O2_costs0.c: Adjust scan-assembler-times count for the hard_float target. * gcc.target/xtensa/elim_callee_saved.c: Likewise. * gcc.target/xtensa/double-conv.c: New test. * gcc.target/xtensa/float-conv.c: New test. Diff: --- gcc/config/xtensa/constraints.md | 4 +- gcc/config/xtensa/xtensa-protos.h | 2 +- gcc/config/xtensa/xtensa.cc | 184 +++++++--- gcc/config/xtensa/xtensa.h | 26 +- gcc/config/xtensa/xtensa.md | 369 ++++++++++++--------- .../gcc.target/xtensa/constsynthV2_O2_costs0.c | 3 +- gcc/testsuite/gcc.target/xtensa/double-conv.c | 44 +++ .../gcc.target/xtensa/elim_callee_saved.c | 3 +- gcc/testsuite/gcc.target/xtensa/float-conv.c | 31 ++ 9 files changed, 445 insertions(+), 221 deletions(-) diff --git a/gcc/config/xtensa/constraints.md b/gcc/config/xtensa/constraints.md index bd1b77da2908..0344bed6e3b5 100644 --- a/gcc/config/xtensa/constraints.md +++ b/gcc/config/xtensa/constraints.md @@ -133,9 +133,9 @@ (match_test "rval->cl == rvc_zero && rval->sign == 0"))) (define_constraint "Gc" - "A single Floating-point constant for use with CONST.S instructions." + "A single Floating-point constant for use with CONST.[SD] instructions." (and (match_code "const_double") - (match_test "TARGET_HARD_FLOAT_CONST_S && xtensa_fp_const (rval) >= 0"))) + (match_test "TARGET_HARD_FLOAT_CONST && xtensa_fp_const (rval) >= 0"))) ;; Memory constraints. diff --git a/gcc/config/xtensa/xtensa-protos.h b/gcc/config/xtensa/xtensa-protos.h index f6fa6c40d331..472b6c3d6c45 100644 --- a/gcc/config/xtensa/xtensa-protos.h +++ b/gcc/config/xtensa/xtensa-protos.h @@ -40,7 +40,7 @@ extern bool constantpool_address_p (const_rtx); extern int constantpool_mem_p (rtx); extern void xtensa_extend_reg (rtx, rtx); extern void xtensa_expand_conditional_branch (rtx *, machine_mode); -extern int xtensa_expand_conditional_move (rtx *, int); +extern int xtensa_expand_conditional_move (rtx *, machine_mode); extern int xtensa_expand_scc (rtx *, machine_mode); extern int xtensa_expand_block_move (rtx *); extern int xtensa_expand_block_set (rtx *); diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc index 99a244bf9fdc..d7420fffec24 100644 --- a/gcc/config/xtensa/xtensa.cc +++ b/gcc/config/xtensa/xtensa.cc @@ -180,6 +180,7 @@ static bool xtensa_member_type_forces_blk (const_tree, static void xtensa_conditional_register_usage (void); static unsigned int xtensa_hard_regno_nregs (unsigned int, machine_mode); +static unsigned char xtensa_class_max_nregs (reg_class_t, machine_mode); static bool xtensa_hard_regno_mode_ok (unsigned int, machine_mode); static bool xtensa_modes_tieable_p (machine_mode, machine_mode); static HOST_WIDE_INT xtensa_constant_alignment (const_tree, HOST_WIDE_INT); @@ -339,6 +340,10 @@ static tree xtensa_handle_force_l32_attribute (tree *, tree, tree, int, bool *); #undef TARGET_HARD_REGNO_NREGS #define TARGET_HARD_REGNO_NREGS xtensa_hard_regno_nregs + +#undef TARGET_CLASS_MAX_NREGS +#define TARGET_CLASS_MAX_NREGS xtensa_class_max_nregs + #undef TARGET_HARD_REGNO_MODE_OK #define TARGET_HARD_REGNO_MODE_OK xtensa_hard_regno_mode_ok @@ -857,25 +862,26 @@ gen_float_relational (enum rtx_code test_code, /* relational test (EQ, etc) */ rtx (*gen_fn) (rtx, rtx, rtx); rtx brtmp; int reverse_regs, invert; + bool sf = GET_MODE (cmp0) == E_SFmode; switch (test_code) { - case EQ: reverse_regs = 0; invert = 0; gen_fn = gen_seq_sf; break; - case NE: reverse_regs = 0; invert = 1; gen_fn = gen_seq_sf; break; - case LE: reverse_regs = 0; invert = 0; gen_fn = gen_sle_sf; break; - case GT: reverse_regs = 1; invert = 0; gen_fn = gen_slt_sf; break; - case LT: reverse_regs = 0; invert = 0; gen_fn = gen_slt_sf; break; - case GE: reverse_regs = 1; invert = 0; gen_fn = gen_sle_sf; break; - case UNEQ: reverse_regs = 0; invert = 0; gen_fn = gen_suneq_sf; break; - case LTGT: reverse_regs = 0; invert = 1; gen_fn = gen_suneq_sf; break; - case UNLE: reverse_regs = 0; invert = 0; gen_fn = gen_sunle_sf; break; - case UNGT: reverse_regs = 1; invert = 0; gen_fn = gen_sunlt_sf; break; - case UNLT: reverse_regs = 0; invert = 0; gen_fn = gen_sunlt_sf; break; - case UNGE: reverse_regs = 1; invert = 0; gen_fn = gen_sunle_sf; break; + case EQ: reverse_regs = 0; invert = 0; gen_fn = sf ? gen_seq_sf : gen_seq_df; break; + case NE: reverse_regs = 0; invert = 1; gen_fn = sf ? gen_seq_sf : gen_seq_df; break; + case LE: reverse_regs = 0; invert = 0; gen_fn = sf ? gen_sle_sf : gen_sle_df; break; + case GT: reverse_regs = 1; invert = 0; gen_fn = sf ? gen_slt_sf : gen_slt_df; break; + case LT: reverse_regs = 0; invert = 0; gen_fn = sf ? gen_slt_sf : gen_slt_df; break; + case GE: reverse_regs = 1; invert = 0; gen_fn = sf ? gen_sle_sf : gen_sle_df; break; + case UNEQ: reverse_regs = 0; invert = 0; gen_fn = sf ? gen_suneq_sf : gen_suneq_df; break; + case LTGT: reverse_regs = 0; invert = 1; gen_fn = sf ? gen_suneq_sf : gen_suneq_df; break; + case UNLE: reverse_regs = 0; invert = 0; gen_fn = sf ? gen_sunle_sf : gen_sunle_df; break; + case UNGT: reverse_regs = 1; invert = 0; gen_fn = sf ? gen_sunlt_sf : gen_sunlt_df; break; + case UNLT: reverse_regs = 0; invert = 0; gen_fn = sf ? gen_sunlt_sf : gen_sunlt_df; break; + case UNGE: reverse_regs = 1; invert = 0; gen_fn = sf ? gen_sunle_sf : gen_sunle_df; break; case UNORDERED: - reverse_regs = 0; invert = 0; gen_fn = gen_sunordered_sf; break; + reverse_regs = 0; invert = 0; gen_fn = sf ? gen_sunordered_sf : gen_sunordered_df; break; case ORDERED: - reverse_regs = 0; invert = 1; gen_fn = gen_sunordered_sf; break; + reverse_regs = 0; invert = 1; gen_fn = sf ? gen_sunordered_sf : gen_sunordered_df; break; default: fatal_insn ("bad test", gen_rtx_fmt_ee (test_code, VOIDmode, cmp0, cmp1)); reverse_regs = 0; invert = 0; gen_fn = 0; /* avoid compiler warnings */ @@ -902,14 +908,21 @@ xtensa_expand_conditional_branch (rtx *operands, machine_mode mode) switch (mode) { case E_SFmode: - if (TARGET_HARD_FLOAT) + if (TARGET_FLOAT32) { cmp = gen_float_relational (test_code, cmp0, cmp1); break; } - /* FALLTHRU */ + fatal_insn ("bad test", gen_rtx_fmt_ee (test_code, VOIDmode, cmp0, cmp1)); case E_DFmode: + if (TARGET_FLOAT64) + { + cmp = gen_float_relational (test_code, cmp0, cmp1); + break; + } + /* FALLTHRU */ + default: fatal_insn ("bad test", gen_rtx_fmt_ee (test_code, VOIDmode, cmp0, cmp1)); @@ -992,7 +1005,8 @@ gen_conditional_move (enum rtx_code code, machine_mode mode, return gen_rtx_fmt_ee (code, VOIDmode, op0, op1); } - if (TARGET_HARD_FLOAT && mode == SFmode) + if ((TARGET_FLOAT32 && mode == SFmode) + || (TARGET_FLOAT64 && mode == DFmode)) return gen_float_relational (code, op0, op1); return 0; @@ -1000,7 +1014,7 @@ gen_conditional_move (enum rtx_code code, machine_mode mode, int -xtensa_expand_conditional_move (rtx *operands, int isflt) +xtensa_expand_conditional_move (rtx *operands, machine_mode mode) { rtx dest = operands[0]; rtx cmp = operands[1]; @@ -1011,14 +1025,29 @@ xtensa_expand_conditional_move (rtx *operands, int isflt) XEXP (cmp, 0), XEXP (cmp, 1)))) return 0; - if (isflt) - gen_fn = (cmp_mode == SImode - ? gen_movsfcc_internal0 - : gen_movsfcc_internal1); - else - gen_fn = (cmp_mode == SImode - ? gen_movsicc_internal0 - : gen_movsicc_internal1); + switch (mode) + { + case E_SImode: + gen_fn = (cmp_mode == SImode + ? gen_movsicc_internal0 + : gen_movsicc_internal1); + break; + + case E_SFmode: + gen_fn = (cmp_mode == SImode + ? gen_movsfcc_internal0 + : gen_movsfcc_internal1); + break; + + case E_DFmode: + gen_fn = (cmp_mode == SImode + ? gen_movdfcc_internal0 + : gen_movdfcc_internal1); + break; + + default: + gcc_unreachable (); + } emit_insn (gen_fn (dest, XEXP (cmp, 0), operands[2], operands[3], cmp)); return 1; @@ -1300,6 +1329,8 @@ xtensa_copy_incoming_a7 (rtx opnd) switch (mode) { case E_DFmode: + emit_insn (gen_movdf_internal (tmp, gen_raw_REG (mode, A7_REG - 1))); + break; case E_DImode: /* Copy the value out of A7 here but keep the first word in A6 until after the set_frame_ptr insn. Otherwise, the register allocator @@ -1307,6 +1338,8 @@ xtensa_copy_incoming_a7 (rtx opnd) value. */ emit_insn (gen_movsi_internal (gen_rtx_SUBREG (SImode, tmp, 4), gen_raw_REG (SImode, A7_REG))); + emit_insn (gen_movsi_internal (gen_rtx_SUBREG (SImode, tmp, 0), + gen_rtx_REG (SImode, A7_REG - 1))); break; case E_SFmode: emit_insn (gen_movsf_internal (tmp, gen_raw_REG (mode, A7_REG))); @@ -1326,10 +1359,6 @@ xtensa_copy_incoming_a7 (rtx opnd) cfun->machine->set_frame_ptr_insn = emit_insn (gen_set_frame_ptr ()); - /* For DF and DI mode arguments, copy the incoming value in A6 now. */ - if (mode == DFmode || mode == DImode) - emit_insn (gen_movsi_internal (gen_rtx_SUBREG (SImode, tmp, 0), - gen_rtx_REG (SImode, A7_REG - 1))); entry_insns = end_sequence (); if (cfun->machine->vararg_a7) @@ -2103,6 +2132,8 @@ xtensa_emit_movcc (bool inverted, bool isfp, bool isbool, rtx *operands) static char result[64]; enum rtx_code code; const char *op; + const char *dot_suffix = ""; + int n; code = GET_CODE (operands[4]); if (inverted) @@ -2127,9 +2158,26 @@ xtensa_emit_movcc (bool inverted, bool isfp, bool isbool, rtx *operands) default: gcc_unreachable (); } } + if (isfp) + { + switch (GET_MODE (operands[0])) + { + case E_SFmode: dot_suffix = ".s"; break; + case E_DFmode: dot_suffix = ".s"; break; /* It should be .d, but this + is supposed to be a macro + and it's missing in the + assembler. */ + default: gcc_unreachable (); + } + } - sprintf (result, "mov%s%s\t%%0, %%%d, %%1", - op, isfp ? ".s" : "", inverted ? 3 : 2); + n = sprintf (result, "mov%s%s\t%%0, %%%d, %%1", + op, dot_suffix, inverted ? 3 : 2); + if (!isfp && GET_MODE (operands[0]) == E_DFmode) + { + sprintf (result + n, " ; mov%s\t%%D0, %%D%d, %%1", + op, inverted ? 3 : 2); + } return result; } @@ -3000,7 +3048,8 @@ xtensa_option_override (void) else if (GP_REG_P (regno)) temp = ((regno & 1) == 0 || (size <= UNITS_PER_WORD)); else if (FP_REG_P (regno)) - temp = (TARGET_HARD_FLOAT && (mode == SFmode)); + temp = ((TARGET_FLOAT32 && mode == SFmode) + || (TARGET_FLOAT64 && mode == DFmode)); else if (BR_REG_P (regno)) temp = (TARGET_BOOLEANS && (mode == CCmode)); else @@ -3070,6 +3119,16 @@ xtensa_hard_regno_nregs (unsigned int regno, machine_mode mode) return CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD); } +/* Implement TARGET_CLASS_MAX_NREGS. */ + +static unsigned char +xtensa_class_max_nregs (reg_class_t rclass, machine_mode mode) +{ + if (rclass == FP_REGS) + return CEIL (GET_MODE_SIZE (mode), UNITS_PER_FPREG); + return CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD); +} + /* Implement TARGET_HARD_REGNO_MODE_OK. */ static bool @@ -3123,6 +3182,8 @@ xtensa_modes_tieable_p (machine_mode mode1, machine_mode mode2) 'G', CONST_DOUBLE:SF, print 0~3 when rval is 0.0f, 1.0f, 2.0f, or 0.5f, respectively. 'D' REG, print second register of double-word register operand + 'T' REG, print register holding top bits of double-word register operand + 'B' REG, print register holding bottom bits of double-word register operand 'N' MEM, print address of next word following a memory operand 'v' MEM, if memory reference is volatile, output a MEMW before it 't' any constant, add "@h" suffix for top 16 bits @@ -3157,6 +3218,20 @@ print_operand (FILE *file, rtx x, int letter) output_operand_lossage ("invalid %%D value"); break; + case 'T': + if (REG_P (x) || SUBREG_P (x)) + fprintf (file, "%s", reg_names[xt_true_regnum (x) + !TARGET_BIG_ENDIAN]); + else + output_operand_lossage ("invalid %%T value"); + break; + + case 'B': + if (REG_P (x) || SUBREG_P (x)) + fprintf (file, "%s", reg_names[xt_true_regnum (x) + !!TARGET_BIG_ENDIAN]); + else + output_operand_lossage ("invalid %%B value"); + break; + case 'v': if (MEM_P (x)) { @@ -3219,21 +3294,21 @@ print_operand (FILE *file, rtx x, int letter) break; case 'U': - if (CONST_DOUBLE_P (x) && GET_MODE (x) == SFmode) + if (CONST_DOUBLE_P (x) && (GET_MODE (x) == SFmode || GET_MODE (x) == DFmode)) fprintf (file, "%d", REAL_EXP (CONST_DOUBLE_REAL_VALUE (x)) - 1); else output_operand_lossage ("invalid %%U value"); break; case 'V': - if (CONST_DOUBLE_P (x) && GET_MODE (x) == SFmode) + if (CONST_DOUBLE_P (x) && (GET_MODE (x) == SFmode || GET_MODE (x) == DFmode)) fprintf (file, "%d", 1 - REAL_EXP (CONST_DOUBLE_REAL_VALUE (x))); else output_operand_lossage ("invalid %%V value"); break; case 'G': - if (CONST_DOUBLE_P (x) && GET_MODE (x) == SFmode) + if (CONST_DOUBLE_P (x) && (GET_MODE (x) == SFmode || GET_MODE (x) == DFmode)) fprintf (file, "%d", xtensa_fp_const (CONST_DOUBLE_REAL_VALUE (x))); else output_operand_lossage ("invalid %%G value"); @@ -4670,9 +4745,9 @@ xtensa_rtx_costs (rtx x, machine_mode mode, int outer_code, case NEG: { if (mode == SFmode) - *total = COSTS_N_INSNS (TARGET_HARD_FLOAT ? 1 : 50); + *total = COSTS_N_INSNS (TARGET_FLOAT32 ? 1 : 50); else if (mode == DFmode) - *total = COSTS_N_INSNS (50); + *total = COSTS_N_INSNS (TARGET_FLOAT64 ? 1 : 50); else if (mode == DImode) *total = COSTS_N_INSNS (4); else @@ -4684,8 +4759,10 @@ xtensa_rtx_costs (rtx x, machine_mode mode, int outer_code, case MINUS: { if (mode == SFmode) - *total = COSTS_N_INSNS (TARGET_HARD_FLOAT ? 1 : 50); - else if (mode == DFmode || mode == DImode) + *total = COSTS_N_INSNS (TARGET_FLOAT32 ? 1 : 50); + else if (mode == DFmode) + *total = COSTS_N_INSNS (TARGET_FLOAT64 ? 1 : 50); + else if (mode == DImode) *total = COSTS_N_INSNS (50); else *total = COSTS_N_INSNS (1); @@ -4695,9 +4772,9 @@ xtensa_rtx_costs (rtx x, machine_mode mode, int outer_code, case MULT: { if (mode == SFmode) - *total = COSTS_N_INSNS (TARGET_HARD_FLOAT ? 4 : 50); + *total = COSTS_N_INSNS (TARGET_FLOAT32 ? 4 : 50); else if (mode == DFmode) - *total = COSTS_N_INSNS (50); + *total = COSTS_N_INSNS (TARGET_FLOAT64 ? 4 : 50); else if (mode == DImode) *total = COSTS_N_INSNS (TARGET_MUL32_HIGH ? 10 : 50); else if (TARGET_MUL32) @@ -4716,12 +4793,12 @@ xtensa_rtx_costs (rtx x, machine_mode mode, int outer_code, { if (mode == SFmode) { - *total = COSTS_N_INSNS (TARGET_HARD_FLOAT_DIV ? 8 : 50); + *total = COSTS_N_INSNS (TARGET_FLOAT32_DIV ? 8 : 50); return true; } else if (mode == DFmode) { - *total = COSTS_N_INSNS (50); + *total = COSTS_N_INSNS (TARGET_FLOAT64_DIV ? 8 : 50); return true; } } @@ -4741,7 +4818,9 @@ xtensa_rtx_costs (rtx x, machine_mode mode, int outer_code, case SQRT: if (mode == SFmode) - *total = COSTS_N_INSNS (TARGET_HARD_FLOAT_SQRT ? 8 : 50); + *total = COSTS_N_INSNS (TARGET_FLOAT32_SQRT ? 8 : 50); + else if (mode == DFmode) + *total = COSTS_N_INSNS (TARGET_FLOAT64_SQRT ? 8 : 50); else *total = COSTS_N_INSNS (50); return true; @@ -5112,11 +5191,14 @@ xtensa_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x) || ! xtensa_postreload_completed_p () || xtensa_simm12b (INTVAL (x)); - if (CONST_DOUBLE_P (x) && GET_MODE (x) == SFmode) + if (CONST_DOUBLE_P (x) && (GET_MODE (x) == SFmode || GET_MODE (x) == DFmode)) { int i = xtensa_fp_const (CONST_DOUBLE_REAL_VALUE (x)); - return i == 0 || (TARGET_HARD_FLOAT_CONST_S && i > 0); + return i == 0 || (TARGET_HARD_FLOAT_CONST && + ((GET_MODE (x) == SFmode && TARGET_FLOAT32) + || (GET_MODE (x) == DFmode && TARGET_FLOAT64)) + && i > 0); } return !xtensa_tls_referenced_p (x); @@ -5603,7 +5685,11 @@ xtensa_zero_call_used_regs (HARD_REG_SET selected_regs) rtvec_alloc (0), UNKNOWN_LOCATION)); } - else if (TARGET_HARD_FLOAT && FP_REG_P (regno)) + else if (TARGET_FLOAT64 && FP_REG_P (regno)) + emit_insn (gen_movdf_concat (gen_rtx_REG (DFmode, regno), + gen_rtx_REG (SImode, zeroed_regno), + gen_rtx_REG (SImode, zeroed_regno))); + else if (TARGET_FLOAT32 && FP_REG_P (regno)) emit_move_insn (gen_rtx_REG (SFmode, regno), gen_rtx_REG (SFmode, zeroed_regno)); else if (TARGET_MAC16 && ACC_REG_P (regno)) @@ -5912,7 +5998,7 @@ FPreg_neg_scaled_simm12b (rtx_insn *insn) REG_DEAD (reg:SF gpr) where cst is a negatively-scaled signed 12-bit integer immediate value. */ - if (TARGET_HARD_FLOAT && !TARGET_CONST16 + if (TARGET_FLOAT32 && !TARGET_CONST16 && GET_CODE (pat = PATTERN (insn)) == SET && REG_P (dest = SET_DEST (pat)) && GP_REG_P (REGNO (dest)) && GET_MODE (dest) == SFmode diff --git a/gcc/config/xtensa/xtensa.h b/gcc/config/xtensa/xtensa.h index ae0f32bbb2e8..3a98ea9f08d3 100644 --- a/gcc/config/xtensa/xtensa.h +++ b/gcc/config/xtensa/xtensa.h @@ -38,11 +38,17 @@ along with GCC; see the file COPYING3. If not see #define TARGET_CLAMPS XCHAL_HAVE_CLAMPS #define TARGET_DEPBITS XCHAL_HAVE_DEPBITS #define TARGET_BOOLEANS XCHAL_HAVE_BOOLEANS -#define TARGET_HARD_FLOAT XCHAL_HAVE_FP -#define TARGET_HARD_FLOAT_DIV XCHAL_HAVE_FP_DIV -#define TARGET_HARD_FLOAT_RECIP XCHAL_HAVE_FP_RECIP -#define TARGET_HARD_FLOAT_SQRT XCHAL_HAVE_FP_SQRT -#define TARGET_HARD_FLOAT_RSQRT XCHAL_HAVE_FP_RSQRT +#define TARGET_HARD_FLOAT (XCHAL_HAVE_FP || XCHAL_HAVE_DFP) +#define TARGET_FLOAT32 XCHAL_HAVE_FP +#define TARGET_FLOAT64 XCHAL_HAVE_DFP +#define TARGET_FLOAT32_DIV XCHAL_HAVE_FP_DIV +#define TARGET_FLOAT32_RECIP XCHAL_HAVE_FP_RECIP +#define TARGET_FLOAT32_SQRT XCHAL_HAVE_FP_SQRT +#define TARGET_FLOAT32_RSQRT XCHAL_HAVE_FP_RSQRT +#define TARGET_FLOAT64_DIV XCHAL_HAVE_DFP_DIV +#define TARGET_FLOAT64_RECIP XCHAL_HAVE_DFP_RECIP +#define TARGET_FLOAT64_SQRT XCHAL_HAVE_DFP_SQRT +#define TARGET_FLOAT64_RSQRT XCHAL_HAVE_DFP_RSQRT #define TARGET_HARD_FLOAT_POSTINC XCHAL_HAVE_FP_POSTINC #define TARGET_ABS XCHAL_HAVE_ABS #define TARGET_ADDX XCHAL_HAVE_ADDX @@ -58,9 +64,11 @@ along with GCC; see the file COPYING3. If not see #define TARGET_SALT (XTENSA_MARCH_EARLIEST >= 270000) #define TARGET_DEFAULT (MASK_SERIALIZE_VOLATILE) -#define TARGET_HARD_FLOAT_CONST_S \ - (TARGET_HARD_FLOAT_DIV || TARGET_HARD_FLOAT_RECIP \ - || TARGET_HARD_FLOAT_SQRT || TARGET_HARD_FLOAT_RSQRT) +#define TARGET_HARD_FLOAT_CONST \ + (TARGET_FLOAT32_DIV || TARGET_FLOAT32_RECIP \ + || TARGET_FLOAT32_SQRT || TARGET_FLOAT32_RSQRT \ + || TARGET_FLOAT64_DIV || TARGET_FLOAT64_RECIP \ + || TARGET_FLOAT64_SQRT || TARGET_FLOAT64_RSQRT) #ifndef HAVE_AS_TLS #define HAVE_AS_TLS 0 @@ -117,7 +125,7 @@ along with GCC; see the file COPYING3. If not see #define MIN_UNITS_PER_WORD 4 /* Width of a floating point register. */ -#define UNITS_PER_FPREG 4 +#define UNITS_PER_FPREG (TARGET_FLOAT64 ? 8 : 4) /* Size in bits of various types on the target machine. */ #define INT_TYPE_SIZE 32 diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md index 1bc05a8bdc74..0f5719e0644a 100644 --- a/gcc/config/xtensa/xtensa.md +++ b/gcc/config/xtensa/xtensa.md @@ -44,6 +44,7 @@ UNSPEC_CEIL UNSPEC_FLOOR UNSPEC_ROUND + UNSPEC_CONCAT ]) (define_c_enum "unspecv" [ @@ -91,6 +92,11 @@ (define_mode_iterator HQI [HI QI]) (define_mode_attr mode_bits [(HI "16") (QI "8")]) +;; Single/Double precision floating point iterator +(define_mode_iterator SDF [SF DF]) +(define_mode_attr sd [(SF "s") (DF "d")]) +(define_mode_attr sdf_mode_bits [(SF "32") (DF "64")]) + ;; This iterator and attribute allow signed/unsigned FP truncations to be ;; generated from one template. (define_code_iterator any_fix [fix unsigned_fix]) @@ -307,14 +313,14 @@ (const_int 5) (const_int 6)))]) -(define_insn "addsf3" - [(set (match_operand:SF 0 "register_operand" "=f") - (plus:SF (match_operand:SF 1 "register_operand" "%f") - (match_operand:SF 2 "register_operand" "f")))] - "TARGET_HARD_FLOAT" - "add.s\t%0, %1, %2" +(define_insn "add<mode>3" + [(set (match_operand:SDF 0 "register_operand" "=f") + (plus:SDF (match_operand:SDF 1 "register_operand" "%f") + (match_operand:SDF 2 "register_operand" "f")))] + "TARGET_FLOAT<sdf_mode_bits>" + "add.<sd>\t%0, %1, %2" [(set_attr "type" "fmadd") - (set_attr "mode" "SF") + (set_attr "mode" "<MODE>") (set_attr "length" "3")]) @@ -377,14 +383,14 @@ DONE; }) -(define_insn "subsf3" - [(set (match_operand:SF 0 "register_operand" "=f") - (minus:SF (match_operand:SF 1 "register_operand" "f") - (match_operand:SF 2 "register_operand" "f")))] - "TARGET_HARD_FLOAT" - "sub.s\t%0, %1, %2" +(define_insn "sub<mode>3" + [(set (match_operand:SDF 0 "register_operand" "=f") + (minus:SDF (match_operand:SDF 1 "register_operand" "f") + (match_operand:SDF 2 "register_operand" "f")))] + "TARGET_FLOAT<sdf_mode_bits>" + "sub.<sd>\t%0, %1, %2" [(set_attr "type" "fmadd") - (set_attr "mode" "SF") + (set_attr "mode" "<MODE>") (set_attr "length" "3")]) @@ -486,37 +492,37 @@ (set_attr "mode" "SI") (set_attr "length" "3")]) -(define_insn "mulsf3" - [(set (match_operand:SF 0 "register_operand" "=f") - (mult:SF (match_operand:SF 1 "register_operand" "%f") - (match_operand:SF 2 "register_operand" "f")))] - "TARGET_HARD_FLOAT" - "mul.s\t%0, %1, %2" +(define_insn "mul<mode>3" + [(set (match_operand:SDF 0 "register_operand" "=f") + (mult:SDF (match_operand:SDF 1 "register_operand" "%f") + (match_operand:SDF 2 "register_operand" "f")))] + "TARGET_FLOAT<sdf_mode_bits>" + "mul.<sd>\t%0, %1, %2" [(set_attr "type" "fmadd") - (set_attr "mode" "SF") + (set_attr "mode" "<MODE>") (set_attr "length" "3")]) -(define_insn "fmasf4" - [(set (match_operand:SF 0 "register_operand" "=f") - (fma:SF (match_operand:SF 1 "register_operand" "f") - (match_operand:SF 2 "register_operand" "f") - (match_operand:SF 3 "register_operand" "0")))] - "TARGET_HARD_FLOAT" - "madd.s\t%0, %1, %2" +(define_insn "fma<mode>4" + [(set (match_operand:SDF 0 "register_operand" "=f") + (fma:SDF (match_operand:SDF 1 "register_operand" "f") + (match_operand:SDF 2 "register_operand" "f") + (match_operand:SDF 3 "register_operand" "0")))] + "TARGET_FLOAT<sdf_mode_bits>" + "madd.<sd>\t%0, %1, %2" [(set_attr "type" "fmadd") - (set_attr "mode" "SF") + (set_attr "mode" "<MODE>") (set_attr "length" "3")]) ;; Note that (C - A*B) = (-A*B + C) -(define_insn "fnmasf4" - [(set (match_operand:SF 0 "register_operand" "=f") - (fma:SF (neg:SF (match_operand:SF 1 "register_operand" "f")) - (match_operand:SF 2 "register_operand" "f") - (match_operand:SF 3 "register_operand" "0")))] - "TARGET_HARD_FLOAT" - "msub.s\t%0, %1, %2" +(define_insn "fnma<mode>4" + [(set (match_operand:SDF 0 "register_operand" "=f") + (fma:SDF (neg:SDF (match_operand:SDF 1 "register_operand" "f")) + (match_operand:SDF 2 "register_operand" "f") + (match_operand:SDF 3 "register_operand" "0")))] + "TARGET_FLOAT<sdf_mode_bits>" + "msub.<sd>\t%0, %1, %2" [(set_attr "type" "fmadd") - (set_attr "mode" "SF") + (set_attr "mode" "<MODE>") (set_attr "length" "3")]) @@ -577,13 +583,13 @@ (set_attr "mode" "SI") (set_attr "length" "3")]) -(define_insn "abssf2" - [(set (match_operand:SF 0 "register_operand" "=f") - (abs:SF (match_operand:SF 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT" - "abs.s\t%0, %1" +(define_insn "abs<mode>2" + [(set (match_operand:SDF 0 "register_operand" "=f") + (abs:SDF (match_operand:SDF 1 "register_operand" "f")))] + "TARGET_FLOAT<sdf_mode_bits>" + "abs.<sd>\t%0, %1" [(set_attr "type" "farith") - (set_attr "mode" "SF") + (set_attr "mode" "<MODE>") (set_attr "length" "3")]) @@ -752,14 +758,14 @@ DONE; }) -(define_insn_and_split "negsf2" - [(set (match_operand:SF 0 "register_operand") - (neg:SF (match_operand:SF 1 "register_operand"))) +(define_insn_and_split "neg<mode>2" + [(set (match_operand:SDF 0 "register_operand") + (neg:SDF (match_operand:SDF 1 "register_operand"))) (clobber (match_scratch:SI 2))] - "TARGET_HARD_FLOAT" + "TARGET_FLOAT<sdf_mode_bits>" {@ [cons: =0, 1, =2; attrs: type, length] [D, D, &a; arith , 7] # - [f, f, X; farith, 3] neg.s\t%0, %1 + [f, f, X; farith, 3] neg.<sd>\t%0, %1 } "&& reload_completed && REG_P (operands[2])" [(set (match_dup 2) @@ -767,11 +773,17 @@ (set (match_dup 2) (ashift:SI (match_dup 2) (const_int 31))) - (set (subreg:SI (match_dup 0) 0) - (plus:SI (subreg:SI (match_dup 1) 0) + (set (match_dup 3) + (plus:SI (match_dup 4) (match_dup 2)))] - "" - [(set_attr "mode" "SF")]) +{ + if (GET_MODE_SIZE (SImode) < GET_MODE_SIZE (<MODE>mode)) + emit_insn (gen_movsi (gen_rtx_SUBREG (SImode, operands[0], subreg_lowpart_offset (SImode, <MODE>mode)), + gen_rtx_SUBREG (SImode, operands[1], subreg_lowpart_offset (SImode, <MODE>mode)))); + operands[3] = gen_rtx_SUBREG (SImode, operands[0], subreg_highpart_offset (SImode, <MODE>mode)); + operands[4] = gen_rtx_SUBREG (SImode, operands[1], subreg_highpart_offset (SImode, <MODE>mode)); +} + [(set_attr "mode" "<MODE>")]) ;; Logical instructions. @@ -1188,79 +1200,97 @@ ;; Conversions. -(define_insn "fix<s_fix>_truncsfsi2" +(define_insn "fix<s_fix>_trunc<mode>si2" [(set (match_operand:SI 0 "register_operand" "=a") - (any_fix:SI (match_operand:SF 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT" - "<m_fix>.s\t%0, %1, 0" + (any_fix:SI (match_operand:SDF 1 "register_operand" "f")))] + "TARGET_FLOAT<sdf_mode_bits>" + "<m_fix>.<sd>\t%0, %1, 0" [(set_attr "type" "fconv") - (set_attr "mode" "SF") + (set_attr "mode" "<MODE>") (set_attr "length" "3")]) -(define_insn "*fix<s_fix>_truncsfsi2_2x" +(define_insn "*fix<s_fix>_trunc<mode>si2_2x" [(set (match_operand:SI 0 "register_operand" "=a") - (any_fix:SI (plus:SF (match_operand:SF 1 "register_operand" "f") - (match_dup 1))))] - "TARGET_HARD_FLOAT" - "<m_fix>.s\t%0, %1, 1" + (any_fix:SI (plus:SDF (match_operand:SDF 1 "register_operand" "f") + (match_dup 1))))] + "TARGET_FLOAT<sdf_mode_bits>" + "<m_fix>.<sd>\t%0, %1, 1" [(set_attr "type" "fconv") - (set_attr "mode" "SF") + (set_attr "mode" "<MODE>") (set_attr "length" "3")]) -(define_insn "*fix<s_fix>_truncsfsi2_scaled" +(define_insn "*fix<s_fix>_trunc<mode>si2_scaled" [(set (match_operand:SI 0 "register_operand" "=a") - (any_fix:SI (mult:SF (match_operand:SF 1 "register_operand" "f") - (match_operand:SF 2 "fix_scaling_operand" ""))))] - "TARGET_HARD_FLOAT" - "<m_fix>.s\t%0, %1, %U2" + (any_fix:SI (mult:SDF (match_operand:SDF 1 "register_operand" "f") + (match_operand:SDF 2 "fix_scaling_operand" ""))))] + "TARGET_FLOAT<sdf_mode_bits>" + "<m_fix>.<sd>\t%0, %1, %U2" [(set_attr "type" "fconv") - (set_attr "mode" "SF") + (set_attr "mode" "<MODE>") (set_attr "length" "3")]) -(define_insn "float<s_float>sisf2" - [(set (match_operand:SF 0 "register_operand" "=f") - (any_float:SF (match_operand:SI 1 "register_operand" "a")))] - "TARGET_HARD_FLOAT" - "<m_float>.s\t%0, %1, 0" +(define_insn "float<s_float>si<mode>2" + [(set (match_operand:SDF 0 "register_operand" "=f") + (any_float:SDF (match_operand:SI 1 "register_operand" "a")))] + "TARGET_FLOAT<sdf_mode_bits>" + "<m_float>.<sd>\t%0, %1, 0" [(set_attr "type" "fconv") - (set_attr "mode" "SF") + (set_attr "mode" "<MODE>") (set_attr "length" "3")]) -(define_insn "*float<s_float>sisf2_scaled" - [(set (match_operand:SF 0 "register_operand" "=f") - (mult:SF (any_float:SF (match_operand:SI 1 "register_operand" "a")) - (match_operand:SF 2 "float_scaling_operand" "")))] - "TARGET_HARD_FLOAT" - "<m_float>.s\t%0, %1, %V2" +(define_insn "*float<s_float>si<mode>2_scaled" + [(set (match_operand:SDF 0 "register_operand" "=f") + (mult:SDF (any_float:SDF (match_operand:SI 1 "register_operand" "a")) + (match_operand:SDF 2 "float_scaling_operand" "")))] + "TARGET_FLOAT<sdf_mode_bits>" + "<m_float>.<sd>\t%0, %1, %V2" [(set_attr "type" "fconv") - (set_attr "mode" "SF") + (set_attr "mode" "<MODE>") (set_attr "length" "3")]) -(define_insn "l<m_round>sfsi2" +(define_insn "l<m_round><mode>si2" [(set (match_operand:SI 0 "register_operand" "=a") - (unspec:SI [(match_operand:SF 1 "register_operand" "f")] ANY_ROUND))] - "TARGET_HARD_FLOAT" - "<m_round>.s\t%0, %1, 0" + (unspec:SI [(match_operand:SDF 1 "register_operand" "f")] ANY_ROUND))] + "TARGET_FLOAT<sdf_mode_bits>" + "<m_round>.<sd>\t%0, %1, 0" [(set_attr "type" "fconv") - (set_attr "mode" "SF") + (set_attr "mode" "<MODE>") (set_attr "length" "3")]) -(define_insn "*l<m_round>sfsi2_2x" +(define_insn "*l<m_round><mode>si2_2x" [(set (match_operand:SI 0 "register_operand" "=a") - (unspec:SI [(plus:SF (match_operand:SF 1 "register_operand" "f") - (match_dup 1))] ANY_ROUND))] - "TARGET_HARD_FLOAT" - "<m_round>.s\t%0, %1, 1" + (unspec:SI [(plus:SDF (match_operand:SDF 1 "register_operand" "f") + (match_dup 1))] ANY_ROUND))] + "TARGET_FLOAT<sdf_mode_bits>" + "<m_round>.<sd>\t%0, %1, 1" [(set_attr "type" "fconv") - (set_attr "mode" "SF") + (set_attr "mode" "<MODE>") (set_attr "length" "3")]) -(define_insn "*l<m_round>sfsi2_scaled" +(define_insn "*l<m_round><mode>si2_scaled" [(set (match_operand:SI 0 "register_operand" "=a") - (unspec:SI [(mult:SF (match_operand:SF 1 "register_operand" "f") - (match_operand:SF 2 "fix_scaling_operand" ""))] ANY_ROUND))] - "TARGET_HARD_FLOAT" - "<m_round>.s\t%0, %1, %U2" + (unspec:SI [(mult:SDF (match_operand:SDF 1 "register_operand" "f") + (match_operand:SDF 2 "fix_scaling_operand" ""))] ANY_ROUND))] + "TARGET_FLOAT<sdf_mode_bits>" + "<m_round>.<sd>\t%0, %1, %U2" + [(set_attr "type" "fconv") + (set_attr "mode" "<MODE>") + (set_attr "length" "3")]) + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (float_extend:DF (match_operand:SF 1 "register_operand" "f")))] + "TARGET_FLOAT64" + "cvtd.s\t%0, %1" + [(set_attr "type" "fconv") + (set_attr "mode" "DF") + (set_attr "length" "3")]) + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (float_truncate:SF (match_operand:DF 1 "register_operand" "f")))] + "TARGET_FLOAT64" + "cvts.d\t%0, %1" [(set_attr "type" "fconv") (set_attr "mode" "SF") (set_attr "length" "3")]) @@ -1496,7 +1526,7 @@ (match_operand:SI 2 "fpmem_offset_operand" "")))) (set (match_dup 1) (plus:SI (match_dup 1) (match_dup 2)))] - "TARGET_HARD_FLOAT && !TARGET_HARD_FLOAT_POSTINC" + "TARGET_FLOAT32 && !TARGET_HARD_FLOAT_POSTINC" { if (TARGET_SERIALIZE_VOLATILE && volatile_refs_p (PATTERN (insn))) output_asm_insn ("memw", operands); @@ -1512,7 +1542,7 @@ (match_operand:SF 2 "register_operand" "f")) (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))] - "TARGET_HARD_FLOAT && !TARGET_HARD_FLOAT_POSTINC" + "TARGET_FLOAT32 && !TARGET_HARD_FLOAT_POSTINC" { if (TARGET_SERIALIZE_VOLATILE && volatile_refs_p (PATTERN (insn))) output_asm_insn ("memw", operands); @@ -1522,36 +1552,36 @@ (set_attr "mode" "SF") (set_attr "length" "3")]) -(define_insn "*lsip" - [(set (match_operand:SF 0 "register_operand" "=f") - (mem:SF (match_operand:SI 1 "register_operand" "+a"))) +(define_insn "*l<sd>ip" + [(set (match_operand:SDF 0 "register_operand" "=f") + (mem:SDF (match_operand:SI 1 "register_operand" "+a"))) (set (match_dup 1) (plus:SI (match_dup 1) (match_operand:SI 2 "fpmem_offset_operand" "")))] - "TARGET_HARD_FLOAT && TARGET_HARD_FLOAT_POSTINC" + "TARGET_FLOAT<sdf_mode_bits> && TARGET_HARD_FLOAT_POSTINC" { if (TARGET_SERIALIZE_VOLATILE && volatile_refs_p (PATTERN (insn))) output_asm_insn ("memw", operands); - return "lsip\t%0, %1, %2"; + return "l<sd>ip\t%0, %1, %2"; } [(set_attr "type" "fload") - (set_attr "mode" "SF") + (set_attr "mode" "<MODE>") (set_attr "length" "3")]) -(define_insn "*ssip" - [(set (mem:SF (match_operand:SI 0 "register_operand" "+a")) - (match_operand:SF 1 "register_operand" "f")) +(define_insn "*s<sd>ip" + [(set (mem:SDF (match_operand:SI 0 "register_operand" "+a")) + (match_operand:SDF 1 "register_operand" "f")) (set (match_dup 0) (plus:SI (match_dup 0) (match_operand:SI 2 "fpmem_offset_operand" "")))] - "TARGET_HARD_FLOAT && TARGET_HARD_FLOAT_POSTINC" + "TARGET_FLOAT<sdf_mode_bits> && TARGET_HARD_FLOAT_POSTINC" { if (TARGET_SERIALIZE_VOLATILE && volatile_refs_p (PATTERN (insn))) output_asm_insn ("memw", operands); - return "ssip\t%1, %0, %2"; + return "s<sd>ip\t%1, %0, %2"; } [(set_attr "type" "fstore") - (set_attr "mode" "SF") + (set_attr "mode" "<MODE>") (set_attr "length" "3")]) ;; 64-bit floating point moves @@ -1561,7 +1591,8 @@ (match_operand:DF 1 "general_operand" ""))] "" { - if (!TARGET_CONST16 && !TARGET_AUTO_LITPOOLS && CONST_DOUBLE_P (operands[1])) + if (! satisfies_constraint_Gc (operands[1]) + && !TARGET_CONST16 && !TARGET_AUTO_LITPOOLS && CONST_DOUBLE_P (operands[1])) operands[1] = force_const_mem (DFmode, operands[1]); if (!register_operand (operands[0], DFmode) @@ -1577,21 +1608,43 @@ "register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode)" {@ [cons: =0, 1; attrs: type, length] - [a, r; move, 6] # - [a, Y; load, 6] ^ - [W, iF; move, 12] ^ - [a, T; load, 6] ^ - [a, U; load, 6] ^ - [U, r; store, 6] ^ + [D, Gz; move , 4] movi.n\t%T0, 0\;movi.n\t%B0, 0 + [a, Gz; move , 6] movi\t%T0, 0\;movi\t%B0, 0 + [f, Gc; farith, 3] const.d\t%0, %G1 + [f, r; farith, 3] wfrd\t%0, %T1, %B1 + [a, f; farith, 6] rfrd\t%T0, %1\;rfr\t%B0, %1 + [f, f; farith, 3] mov.d\t%0, %1 + [f, U; fload , 3] %v1ldi\t%0, %1 + [U, f; fstore, 3] %v0sdi\t%1, %0 + [a, r; move , 6] df-move-a-from-r\t%0, %1 + [a, Y; load , 6] df-load-a-from-Y\t%0, %1 + [a, T; load , 6] df-load-a-from-T\t%0, %1 + [a, U; load , 6] df-load-a-from-U\t%0, %1 + [U, r; store , 6] df-store-r-to-U\t%0, %1 } "&& reload_completed" [(set (match_dup 0) (match_dup 2)) (set (match_dup 1) (match_dup 3))] { + if ((register_operand (operands[0], DFmode) + && (FP_REG_P (REGNO (operands[0])) || CONSTANT_P (operands[1]))) + || (register_operand (operands[1], DFmode) + && FP_REG_P (REGNO (operands[1])))) + FAIL; xtensa_split_operand_pair (operands, SFmode); } [(set_attr "mode" "DF")]) +(define_insn "movdf_concat" + [(set (match_operand:DF 0 "register_operand" "=f") + (unspec:DF [(match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")] UNSPEC_CONCAT))] + "TARGET_FLOAT64" + "wfrd\t%0, %1, %2" + [(set_attr "type" "farith") + (set_attr "mode" "DF") + (set_attr "length" "3")]) + ;; Block moves (define_expand "cpymemsi" @@ -1912,14 +1965,14 @@ DONE; }) -(define_expand "cbranchsf4" +(define_expand "cbranch<mode>4" [(match_operator 0 "comparison_operator" - [(match_operand:SF 1 "register_operand") - (match_operand:SF 2 "register_operand")]) + [(match_operand:SDF 1 "register_operand") + (match_operand:SDF 2 "register_operand")]) (match_operand 3 "")] - "TARGET_HARD_FLOAT" + "TARGET_FLOAT<sdf_mode_bits>" { - xtensa_expand_conditional_branch (operands, SFmode); + xtensa_expand_conditional_branch (operands, <MODE>mode); DONE; }) @@ -2400,14 +2453,14 @@ DONE; }) -(define_expand "cstoresf4" +(define_expand "cstore<mode>4" [(match_operand:SI 0 "register_operand") (match_operator:SI 1 "comparison_operator" - [(match_operand:SF 2 "register_operand") - (match_operand:SF 3 "register_operand")])] - "TARGET_HARD_FLOAT" + [(match_operand:SDF 2 "register_operand") + (match_operand:SDF 3 "register_operand")])] + "TARGET_FLOAT<sdf_mode_bits>" { - if (!xtensa_expand_scc (operands, SFmode)) + if (!xtensa_expand_scc (operands, <MODE>mode)) FAIL; DONE; }) @@ -2423,19 +2476,19 @@ (match_operand:SI 3 "register_operand" "")))] "" { - if (!xtensa_expand_conditional_move (operands, 0)) + if (!xtensa_expand_conditional_move (operands, SImode)) FAIL; DONE; }) -(define_expand "movsfcc" - [(set (match_operand:SF 0 "register_operand" "") - (if_then_else:SF (match_operand 1 "comparison_operator" "") - (match_operand:SF 2 "register_operand" "") - (match_operand:SF 3 "register_operand" "")))] +(define_expand "mov<mode>cc" + [(set (match_operand:SDF 0 "register_operand" "") + (if_then_else:SDF (match_operand 1 "comparison_operator" "") + (match_operand:SDF 2 "register_operand" "") + (match_operand:SDF 3 "register_operand" "")))] "" { - if (!xtensa_expand_conditional_move (operands, 1)) + if (!xtensa_expand_conditional_move (operands, <MODE>mode)) FAIL; DONE; }) @@ -2468,13 +2521,13 @@ } [(set_attr "mode" "SI")]) -(define_insn "movsfcc_internal0" - [(set (match_operand:SF 0 "register_operand") - (if_then_else:SF (match_operator 4 "branch_operator" - [(match_operand:SI 1 "register_operand") - (const_int 0)]) - (match_operand:SF 2 "register_operand") - (match_operand:SF 3 "register_operand")))] +(define_insn "mov<mode>cc_internal0" + [(set (match_operand:SDF 0 "register_operand") + (if_then_else:SDF (match_operator 4 "branch_operator" + [(match_operand:SI 1 "register_operand") + (const_int 0)]) + (match_operand:SDF 2 "register_operand") + (match_operand:SDF 3 "register_operand")))] "" {@ [cons: =0, 1, 2, 3; attrs: type, length] [a, r, r, 0; move, 3] << xtensa_emit_movcc (false, false, false, operands); @@ -2482,15 +2535,15 @@ [f, r, f, 0; move, 3] << xtensa_emit_movcc (false, true, false, operands); [f, r, 0, f; move, 3] << xtensa_emit_movcc (true, true, false, operands); } - [(set_attr "mode" "SF")]) - -(define_insn "movsfcc_internal1" - [(set (match_operand:SF 0 "register_operand") - (if_then_else:SF (match_operator 4 "boolean_operator" - [(match_operand:CC 1 "register_operand") - (const_int 0)]) - (match_operand:SF 2 "register_operand") - (match_operand:SF 3 "register_operand")))] + [(set_attr "mode" "<MODE>")]) + +(define_insn "mov<mode>cc_internal1" + [(set (match_operand:SDF 0 "register_operand") + (if_then_else:SDF (match_operator 4 "boolean_operator" + [(match_operand:CC 1 "register_operand") + (const_int 0)]) + (match_operand:SDF 2 "register_operand") + (match_operand:SDF 3 "register_operand")))] "TARGET_BOOLEANS" {@ [cons: =0, 1, 2, 3; attrs: type, length] [a, b, r, 0; move, 3] << xtensa_emit_movcc (false, false, true, operands); @@ -2498,17 +2551,17 @@ [f, b, f, 0; move, 3] << xtensa_emit_movcc (false, true, true, operands); [f, b, 0, f; move, 3] << xtensa_emit_movcc (true, true, true, operands); } - [(set_attr "mode" "SF")]) + [(set_attr "mode" "<MODE>")]) ;; Floating-point comparisons. -(define_insn "s<code>_sf" +(define_insn "s<code>_<mode>" [(set (match_operand:CC 0 "register_operand" "=b") - (any_scc_sf:CC (match_operand:SF 1 "register_operand" "f") - (match_operand:SF 2 "register_operand" "f")))] - "TARGET_HARD_FLOAT" - "<scc_sf>.s\t%0, %1, %2" + (any_scc_sf:CC (match_operand:SDF 1 "register_operand" "f") + (match_operand:SDF 2 "register_operand" "f")))] + "TARGET_FLOAT<sdf_mode_bits>" + "<scc_sf>.<sd>\t%0, %1, %2" [(set_attr "type" "farith") (set_attr "mode" "BL") (set_attr "length" "3")]) diff --git a/gcc/testsuite/gcc.target/xtensa/constsynthV2_O2_costs0.c b/gcc/testsuite/gcc.target/xtensa/constsynthV2_O2_costs0.c index a32d75c360ab..7bbee3a26202 100644 --- a/gcc/testsuite/gcc.target/xtensa/constsynthV2_O2_costs0.c +++ b/gcc/testsuite/gcc.target/xtensa/constsynthV2_O2_costs0.c @@ -16,4 +16,5 @@ _Complex double test(int a[], float b[]) return 1-1i; } -/* { dg-final { scan-assembler-times "l32r" 10 } } */ +/* { dg-final { scan-assembler-times "l32r" 10 { target { ! hard_float } } } } */ +/* { dg-final { scan-assembler-times "l32r" 9 { target { hard_float } } } } */ diff --git a/gcc/testsuite/gcc.target/xtensa/double-conv.c b/gcc/testsuite/gcc.target/xtensa/double-conv.c new file mode 100644 index 000000000000..61d839c6a145 --- /dev/null +++ b/gcc/testsuite/gcc.target/xtensa/double-conv.c @@ -0,0 +1,44 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ + +void si(int v); +void ui(unsigned int v); +void f(float v); +void d(double v); + +void dsi(double v) +{ + si(v); +} + +void dui(double v) +{ + ui(v); +} + +void sid(int v) +{ + d(v); +} + +void uid(unsigned int v) +{ + d(v); +} + +void fd(float v) +{ + d(v); +} + +void df(double v) +{ + f(v); +} + +/* { dg-final { scan-assembler-times "trunc.d\t" 2 } } */ +/* { dg-final { scan-assembler-times "utrunc.d\t" 1 } } */ +/* { dg-final { scan-assembler-times "float.d\t" 2 } } */ +/* { dg-final { scan-assembler-times "ufloat.d\t" 1 } } */ +/* { dg-final { scan-assembler-times "cvts.d\t" 1 } } */ +/* { dg-final { scan-assembler-times "cvtd.s\t" 1 } } */ diff --git a/gcc/testsuite/gcc.target/xtensa/elim_callee_saved.c b/gcc/testsuite/gcc.target/xtensa/elim_callee_saved.c index 69e5be35dfd0..47e9613cd458 100644 --- a/gcc/testsuite/gcc.target/xtensa/elim_callee_saved.c +++ b/gcc/testsuite/gcc.target/xtensa/elim_callee_saved.c @@ -34,5 +34,6 @@ int __attribute__((optimize(0))) test3(int a) { return bar() + a; } -/* { dg-final { scan-assembler-times "mov\t|mov.n\t" 20 } } */ +/* { dg-final { scan-assembler-times "mov\t|mov.n\t" 20 { target { ! hard_float } } } } */ +/* { dg-final { scan-assembler-times "mov\t|mov.n\t" 7 { target { hard_float } } } } */ /* { dg-final { scan-assembler-times "a15, 8" 2 } } */ diff --git a/gcc/testsuite/gcc.target/xtensa/float-conv.c b/gcc/testsuite/gcc.target/xtensa/float-conv.c new file mode 100644 index 000000000000..e486018f84ab --- /dev/null +++ b/gcc/testsuite/gcc.target/xtensa/float-conv.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ + +void si(int v); +void ui(unsigned int v); +void f(float v); + +void fsi(float v) +{ + si(v); +} + +void fui(float v) +{ + ui(v); +} + +void sif(int v) +{ + f(v); +} + +void uif(unsigned int v) +{ + f(v); +} + +/* { dg-final { scan-assembler-times "trunc.s\t" 2 } } */ +/* { dg-final { scan-assembler-times "utrunc.s\t" 1 } } */ +/* { dg-final { scan-assembler-times "float.s\t" 2 } } */ +/* { dg-final { scan-assembler-times "ufloat.s\t" 1 } } */
