aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/csky/csky.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/csky/csky.c')
-rw-r--r--gcc/config/csky/csky.c644
1 files changed, 568 insertions, 76 deletions
diff --git a/gcc/config/csky/csky.c b/gcc/config/csky/csky.c
index cdb95fe..6e97994 100644
--- a/gcc/config/csky/csky.c
+++ b/gcc/config/csky/csky.c
@@ -126,7 +126,46 @@ enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER] =
/* Reserved. */
RESERVE_REGS, RESERVE_REGS,
/* Register epc. */
- OTHER_REGS
+ OTHER_REGS,
+ /* Vec registers. */
+ V_REGS, V_REGS, V_REGS, V_REGS,
+ V_REGS, V_REGS, V_REGS, V_REGS,
+ V_REGS, V_REGS, V_REGS, V_REGS,
+ V_REGS, V_REGS, V_REGS, V_REGS,
+ /* Reserved. */
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ /* Reserved. */
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS
};
/* Arrays that map GCC register numbers to debugger register numbers,
@@ -138,11 +177,34 @@ const int csky_dbx_regno[FIRST_PSEUDO_REGISTER] =
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
- -1, -1, 36, 37, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 56, 57, 58, 59,
- 60, 61, 62, 63, 64, 65, 66, 67,
- 68, 69, 70, 71, -1, -1, 72
+ -1, -1, 36, 37,
+ 75, 79, 83, 87, 91, 95, 99, 103,
+ 107, 111, 115, 119, 123, 127, 131, 135,
+ 74, 78, 82, 86, 90, 94, 98, 102,
+ 106, 110, 114, 118, 122, 126, 130, 134,
+ -1, -1, 72,
+ /* vr: 71 - 86 */
+ 139, 143, 147, 151, 155, 159, 163, 167,
+ 171, 175, 179, 183, 187, 191, 195, 199,
+ 138, 142, 146, 150, 154, 158, 162, 166,
+ 170, 174, 178, 182, 186, 190, 194, 198,
+ /* resereved */
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+
+ -1, -1, -1
};
/* Table of machine attributes. */
@@ -351,6 +413,12 @@ csky_cpu_cpp_builtins (cpp_reader *pfile)
builtin_define ("__CSKY_FPUV2__");
}
+ if (TARGET_SUPPORT_FPV3)
+ {
+ builtin_define ("__csky_fpuv3__");
+ builtin_define ("__CSKY_FPUV3__");
+ }
+
if (TARGET_ELRW)
{
builtin_define ("__csky_elrw__");
@@ -408,7 +476,6 @@ csky_cpu_cpp_builtins (cpp_reader *pfile)
* Storage Layout *
******************************************************************/
-
#undef TARGET_PROMOTE_FUNCTION_MODE
#define TARGET_PROMOTE_FUNCTION_MODE \
default_promote_function_mode_always_promote
@@ -416,6 +483,9 @@ csky_cpu_cpp_builtins (cpp_reader *pfile)
#undef TARGET_CONSTANT_ALIGNMENT
#define TARGET_CONSTANT_ALIGNMENT csky_constant_alignment
+#undef TARGET_MANGLE_TYPE
+#define TARGET_MANGLE_TYPE csky_mangle_type
+
/******************************************************************
* Stack Layout and Calling Conventions *
@@ -692,6 +762,15 @@ csky_default_logical_op_non_short_circuit (void)
#define TARGET_SCHED_ADJUST_COST csky_sched_adjust_cost
+/******************************************************************
+ * Builtin *
+ ******************************************************************/
+
+
+#undef TARGET_INIT_BUILTINS
+#define TARGET_INIT_BUILTINS csky_init_builtins
+
+
/* The declaration of functions. */
static void push_csky_minipool_fix (rtx_insn *, HOST_WIDE_INT, rtx *,
machine_mode, rtx);
@@ -837,6 +916,7 @@ Mfix *minipool_fix_tail;
Mfix *minipool_barrier;
/* Allow GC scanning of the minipool obstack. */
+
static void
csky_add_gc_roots (void)
{
@@ -846,6 +926,7 @@ csky_add_gc_roots (void)
/* Implement TARGET_CONSTANT_ALIGNMENT.
Make strings word-aligned so strcpy from constants will be faster. */
+
static HOST_WIDE_INT
csky_constant_alignment (const_tree exp, HOST_WIDE_INT align)
{
@@ -1109,6 +1190,7 @@ get_csky_barrier_cost (rtx_insn *insn)
(FIX->address,MAX_ADDRESS) to forcibly insert a minipool barrier.
Create the barrier by inserting a jump and add a new fix entry for
it. */
+
static Mfix *
create_csky_fix_barrier (Mfix *fix, Mfix *fix_next,
HOST_WIDE_INT max_address)
@@ -1455,6 +1537,7 @@ csky_compute_pushpop_length (rtx *operands)
}
/* Emit constant pools for -mconstpool. */
+
static void
csky_emit_constant_pools (void)
{
@@ -1796,6 +1879,7 @@ csky_initial_elimination_offset (int from, int to)
CUM is a variable of type CUMULATIVE_ARGS which gives info about
the preceding args and about the function being called.
ARG is a description of the argument. */
+
static rtx
csky_function_arg (cumulative_args_t pcum_v, const function_arg_info &arg)
{
@@ -1921,6 +2005,7 @@ csky_function_value (const_tree type, const_tree func,
/* Implement TARGET_LIBCALL_VALUE. */
+
static rtx
csky_libcall_value (machine_mode mode,
const_rtx libcall ATTRIBUTE_UNUSED)
@@ -1949,6 +2034,7 @@ csky_function_value_regno_p (const unsigned int regno)
/* Return an RTX indicating where the return address to the
calling function can be found. */
+
rtx
csky_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
{
@@ -1964,6 +2050,7 @@ csky_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
that must be put in registers. The value must be zero for arguments
that are passed entirely in registers or
that are entirely pushed on the stack. */
+
static int
csky_arg_partial_bytes (cumulative_args_t pcum_v, const function_arg_info &arg)
{
@@ -2180,7 +2267,19 @@ csky_conditional_register_usage (void)
int regno;
for (regno = CSKY_FIRST_VFP_REGNUM;
- regno <= CSKY_LAST_VFP_REGNUM; regno++)
+ regno <= CSKY_LAST_VFP3_REGNUM; regno++)
+ {
+ fixed_regs[regno] = 1;
+ call_used_regs[regno] = 1;
+ }
+ }
+
+ if (!TARGET_SUPPORT_FPV3)
+ {
+ int regno;
+
+ for (regno = CSKY_FIRST_VFP3_REGNUM;
+ regno <= CSKY_LAST_VFP3_REGNUM; regno++)
{
fixed_regs[regno] = 1;
call_used_regs[regno] = 1;
@@ -2198,6 +2297,7 @@ csky_conditional_register_usage (void)
}
/* Implement TARGET_HARD_REGNO_NREGS. */
+
static unsigned int
csky_hard_regno_nregs (unsigned int regno, machine_mode mode)
{
@@ -2261,6 +2361,7 @@ csky_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
/* Implement TARGET_MODES_TIEABLE_P. We can't tie DFmode with other modes
when V_REGs might be in use because those registers mess with the stored
bits. */
+
static bool
csky_modes_tieable_p (machine_mode mode1, machine_mode mode2)
{
@@ -2272,6 +2373,7 @@ csky_modes_tieable_p (machine_mode mode1, machine_mode mode2)
/* Implement TARGET_CAN_CHANGE_MODE_CLASS.
V_REG registers can't do subreg as all values are reformatted to
internal precision. */
+
static bool
csky_can_change_mode_class (machine_mode from,
machine_mode to,
@@ -2406,6 +2508,7 @@ csky_spill_class (reg_class_t rclass, machine_mode mode ATTRIBUTE_UNUSED)
/* Convert a static initializer array of feature bits to sbitmap
representation. */
+
static void
csky_initialize_isa (sbitmap isa, const enum csky_isa_feature *isa_bits)
{
@@ -2417,6 +2520,7 @@ csky_initialize_isa (sbitmap isa, const enum csky_isa_feature *isa_bits)
/* Configure a build target TARGET from the user-specified options OPTS and
OPTS_SET. */
+
static void
csky_configure_build_target (struct csky_build_target *target,
struct cl_target_option *opts,
@@ -2508,7 +2612,9 @@ csky_option_override (void)
csky_base_arch = csky_active_target.base_arch;
- if (flag_pic && !(CSKY_TARGET_ARCH (CK810) || CSKY_TARGET_ARCH (CK807)))
+ if (flag_pic && !(CSKY_TARGET_ARCH (CK807)
+ || CSKY_TARGET_ARCH (CK810)
+ || CSKY_TARGET_ARCH (CK860)))
{
flag_pic = 0;
warning (0, "%qs is not supported by arch %s",
@@ -2526,19 +2632,21 @@ csky_option_override (void)
bool ok;
int fpu_index;
-#ifdef CSKY_FPUTYPE_DEFAULT
- target_fpu_name = CSKY_FPUTYPE_DEFAULT;
-#else
- target_fpu_name = "fpv2";
-#endif
-
if (csky_active_target.core_name != NULL
&& !strchr (csky_active_target.core_name, 'f'))
target_fpu_name = "auto";
else if (CSKY_TARGET_ARCH (CK803) || !TARGET_DOUBLE_FLOAT)
target_fpu_name = "fpv2_sf";
+ else if (CSKY_TARGET_ARCH (CK860))
+ target_fpu_name = "fpv3";
else if (TARGET_DOUBLE_FLOAT && TARGET_FDIVDU)
target_fpu_name = "fpv2_divd";
+ else
+#ifdef CSKY_FPUTYPE_DEFAULT
+ target_fpu_name = CSKY_FPUTYPE_DEFAULT;
+#else
+ target_fpu_name = "fpv2";
+#endif
ok = opt_enum_arg_to_value (OPT_mfpu_, target_fpu_name, &fpu_index,
CL_TARGET);
@@ -3020,10 +3128,8 @@ ck810_legitimate_index_p (machine_mode mode, rtx index, int strict_p)
{
enum rtx_code code = GET_CODE (index);
- if (TARGET_HARD_FLOAT
- && (mode == SFmode || mode == DFmode))
- return (code == CONST_INT && INTVAL (index) < 1024
- && INTVAL (index) >= 0
+ if (code == CONST_INT && TARGET_HARD_FLOAT && CSKY_VREG_MODE_P (mode))
+ return (INTVAL (index) < 1024 && INTVAL (index) >= 0
&& (INTVAL (index) & 3) == 0);
if (code == CONST_INT)
@@ -3183,7 +3289,7 @@ static bool
decompose_csky_address (rtx addr, struct csky_address *out)
{
rtx base = NULL_RTX, index = NULL_RTX, disp = NULL_RTX;
- HOST_WIDE_INT scale = 1;
+ HOST_WIDE_INT scale = 0;
rtx scale_rtx = NULL_RTX;
int i;
@@ -3231,7 +3337,10 @@ decompose_csky_address (rtx addr, struct csky_address *out)
if (!base)
base = op;
else if (!index)
- index = op;
+ {
+ index = op;
+ scale = 1;
+ }
else
return false;
break;
@@ -3259,7 +3368,7 @@ decompose_csky_address (rtx addr, struct csky_address *out)
scale_rtx = XEXP (op, 1);
if (!CONST_INT_P (scale_rtx))
return false;
- scale = scale << INTVAL (scale_rtx);
+ scale = 1 << INTVAL (scale_rtx);
break;
default:
return false;
@@ -3484,6 +3593,14 @@ csky_print_operand (FILE *stream, rtx x, int code)
case UNSPEC:
csky_output_pic_addr_const (stream, x, code);
break;
+ case CONST_DOUBLE:
+ {
+ char fpstr[20];
+ real_to_decimal ( fpstr, CONST_DOUBLE_REAL_VALUE (x),
+ sizeof (fpstr), 0, 1);
+ fprintf (stream, "%s", fpstr);
+ }
+ break;
default:
output_addr_const (stream, x);
break;
@@ -3997,17 +4114,37 @@ csky_output_move (rtx insn ATTRIBUTE_UNUSED, rtx operands[],
return "mfhi\t%0";
}
- if (CSKY_VREG_P (dstreg) && CSKY_VREG_P (srcreg))
- return "fmovs\t%0, %1";
- if (CSKY_VREG_P (dstreg))
- return "fmtvrl\t%0, %1";
- if (CSKY_VREG_P (srcreg))
- return "fmfvrl\t%0, %1";
-
- if (REGNO (src) == CSKY_CC_REGNUM)
- return "mvc\t%0";
- else
- return "mov\t%0, %1";
+ if (CSKY_VREG_P (dstreg) && CSKY_VREG_P (srcreg))
+ {
+ if (CSKY_ISA_FEATURE (fpv2_sf))
+ return "fmovs\t%0, %1";
+ else if (CSKY_ISA_FEATURE (fpv3_sf))
+ return "fmov.32\t%0, %1";
+ else
+ gcc_unreachable ();
+ }
+ if (CSKY_VREG_P (dstreg))
+ {
+ if (CSKY_ISA_FEATURE (fpv2_sf))
+ return "fmtvrl\t%0, %1";
+ else if (CSKY_ISA_FEATURE (fpv3_sf))
+ return "fmtvr.32.1\t%0, %1";
+ else
+ gcc_unreachable ();
+ }
+ if (CSKY_VREG_P (srcreg))
+ {
+ if (CSKY_ISA_FEATURE (fpv2_sf))
+ return "fmfvrl\t%0, %1";
+ else if (CSKY_ISA_FEATURE (fpv3_sf))
+ return "fmfvr.32.1\t%0, %1";
+ else
+ gcc_unreachable ();
+ }
+ if (REGNO (src) == CSKY_CC_REGNUM)
+ return "mvc\t%0";
+ else
+ return "mov\t%0, %1";
}
/* The situation mov memory to reg. */
else if (GET_CODE (src) == MEM)
@@ -4018,13 +4155,21 @@ csky_output_move (rtx insn ATTRIBUTE_UNUSED, rtx operands[],
switch (GET_MODE (src))
{
case E_HImode:
+ case E_HFmode:
return "ldr.h\t%0, %1";
case E_QImode:
return "ldr.b\t%0, %1";
case E_SImode:
case E_SFmode:
if (CSKY_VREG_P (REGNO (dst)))
- return "fldrs\t%0, %1";
+ {
+ if (CSKY_ISA_FEATURE(fpv2_sf))
+ return "fldrs\t%0, %1";
+ else if (CSKY_ISA_FEATURE(fpv3_sf))
+ return "fldr.32\t%0, %1";
+ else
+ gcc_unreachable ();
+ }
else
return "ldr.w\t%0, %1";
default:
@@ -4042,13 +4187,21 @@ csky_output_move (rtx insn ATTRIBUTE_UNUSED, rtx operands[],
switch (GET_MODE (src))
{
case E_HImode:
+ case E_HFmode:
return "ld.h\t%0, %1";
case E_QImode:
return "ld.b\t%0, %1";
case E_SFmode:
case E_SImode:
if (CSKY_VREG_P (REGNO (dst)))
- return "flds\t%0, %1";
+ {
+ if (CSKY_ISA_FEATURE(fpv2_sf))
+ return "flds\t%0, %1";
+ else if (CSKY_ISA_FEATURE(fpv3_sf))
+ return "fld.32\t%0, %1";
+ else
+ gcc_unreachable ();
+ }
else
return "ld.w\t%0, %1";
default:
@@ -4106,7 +4259,14 @@ csky_output_move (rtx insn ATTRIBUTE_UNUSED, rtx operands[],
case E_SFmode:
case E_SImode:
if (CSKY_VREG_P (REGNO (src)))
- return "fstrs\t%1, %0";
+ {
+ if (CSKY_ISA_FEATURE(fpv2_sf))
+ return "fstrs\t%1, %0";
+ else if (CSKY_ISA_FEATURE(fpv3_sf))
+ return "fstr.32\t%1, %0";
+ else
+ gcc_unreachable ();
+ }
else
return "str.w\t%1, %0";
default:
@@ -4122,7 +4282,14 @@ csky_output_move (rtx insn ATTRIBUTE_UNUSED, rtx operands[],
case E_SImode:
case E_SFmode:
if (CSKY_VREG_P (REGNO (src)))
- return "fsts\t%1, %0";
+ {
+ if (CSKY_ISA_FEATURE(fpv2_sf))
+ return "fsts\t%1, %0";
+ else if (CSKY_ISA_FEATURE(fpv3_sf))
+ return "fst.32\t%1, %0";
+ else
+ gcc_unreachable ();
+ }
else
return "st.w\t%1, %0";
default:
@@ -4261,7 +4428,14 @@ csky_output_movedouble (rtx operands[],
return "mthi\t%R1\n\tmtlo\t%1";
}
else if (CSKY_VREG_P (srcreg) && CSKY_VREG_P (dstreg))
- return "fmovd\t%0, %1";
+ {
+ if (CSKY_ISA_FEATURE(fpv2_df))
+ return "fmovd\t%0, %1";
+ else if (CSKY_ISA_FEATURE(fpv3_df))
+ return "fmov.64\t%0, %1";
+ else
+ gcc_unreachable ();
+ }
else if (CSKY_VREG_P (srcreg))
{
/* Since the vector registers in fpuv2_soft processors
@@ -4270,18 +4444,46 @@ csky_output_movedouble (rtx operands[],
if (TARGET_SOFT_FPU)
return "fmfvrl\t%0, %1";
else if (TARGET_BIG_ENDIAN)
- return "fmfvrh\t%0, %1\n\tfmfvrl\t%R0, %1";
+ {
+ if (CSKY_ISA_FEATURE(fpv2_df))
+ return "fmfvrh\t%0, %1\n\tfmfvrl\t%R0, %1";
+ else if (CSKY_ISA_FEATURE(fpv3_df))
+ return "fmfvr.64\t%R0, %0, %1";
+ else
+ gcc_unreachable ();
+ }
else
- return "fmfvrh\t%R0, %1\n\tfmfvrl\t%0, %1";
+ {
+ if (CSKY_ISA_FEATURE(fpv2_df))
+ return "fmfvrh\t%R0, %1\n\tfmfvrl\t%0, %1";
+ else if (CSKY_ISA_FEATURE(fpv3_df))
+ return "fmfvr.64\t%0, %R0, %1";
+ else
+ gcc_unreachable ();
+ }
}
else if (CSKY_VREG_P (dstreg))
{
if (TARGET_SOFT_FPU)
return "fmtvrl\t%0, %1";
else if (TARGET_BIG_ENDIAN)
- return "fmtvrh\t%0, %1\n\tfmtvrl\t%0, %R1";
+ {
+ if (CSKY_ISA_FEATURE(fpv2_df))
+ return "fmtvrh\t%0, %1\n\tfmtvrl\t%0, %R1";
+ else if (CSKY_ISA_FEATURE(fpv3_df))
+ return "fmtvr.64\t%0, %R1, %1";
+ else
+ gcc_unreachable ();
+ }
else
- return "fmtvrh\t%0, %R1\n\tfmtvrl\t%0, %1";
+ {
+ if (CSKY_ISA_FEATURE(fpv2_df))
+ return "fmtvrh\t%0, %R1\n\tfmtvrl\t%0, %1";
+ else if (CSKY_ISA_FEATURE(fpv3_df))
+ return "fmtvr.64\t%0, %1, %R1";
+ else
+ gcc_unreachable ();
+ }
}
/* Ensure the second source not overwritten. */
@@ -4323,9 +4525,23 @@ csky_output_movedouble (rtx operands[],
if (CSKY_VREG_P (dstreg))
{
if (op0.index)
- return "fldrd\t%0, %1";
+ {
+ if (CSKY_ISA_FEATURE(fpv2_df))
+ return "fldrd\t%0, %1";
+ else if (CSKY_ISA_FEATURE(fpv3_df))
+ return "fldr.64\t%0, %1";
+ else
+ gcc_unreachable ();
+ }
else
- return "fldd\t%0, %1";
+ {
+ if (CSKY_ISA_FEATURE(fpv2_df))
+ return "fldd\t%0, %1";
+ else if (CSKY_ISA_FEATURE(fpv3_df))
+ return "fld.64\t%0, %1";
+ else
+ gcc_unreachable ();
+ }
}
/* FIXME length attribute is wrong here. */
if (dstreg == basereg)
@@ -4389,9 +4605,23 @@ csky_output_movedouble (rtx operands[],
if (CSKY_VREG_P (srcreg))
{
if (op0.index)
- return "fstrd\t%1, %0";
+ {
+ if (CSKY_ISA_FEATURE(fpv2_df))
+ return "fstrd\t%1, %0";
+ else if (CSKY_ISA_FEATURE(fpv3_df))
+ return "fstr.64\t%1, %0";
+ else
+ gcc_unreachable ();
+ }
else
- return "fstd\t%1, %0";
+ {
+ if (CSKY_ISA_FEATURE(fpv2_df))
+ return "fstd\t%1, %0";
+ else if (CSKY_ISA_FEATURE(fpv3_df))
+ return "fst.64\t%1, %0";
+ else
+ gcc_unreachable ();
+ }
}
/* FIXME length attribute is wrong here. */
if (srcreg == basereg)
@@ -4518,9 +4748,181 @@ csky_output_ck801_movedouble (rtx operands[],
gcc_unreachable ();
}
+/* Calculate the instruction's length for moving double-word data. */
+
+int
+csky_get_movedouble_length(rtx operands[])
+{
+ rtx dst = operands[0];
+ rtx src = operands[1];
+
+ if (REG_P (dst))
+ {
+ if (REG_P (src))
+ {
+ int dstreg = REGNO (dst);
+ int srcreg = REGNO (src);
+
+ if (CSKY_VREG_P (srcreg) && CSKY_VREG_P (dstreg))
+ return 4;
+ else
+ return 8;
+ }
+ else if (GET_CODE (src) == MEM)
+ {
+ rtx memexp = XEXP (src, 0);
+ int dstreg = REGNO (dst);
+ struct csky_address op0;
+ decompose_csky_address (XEXP (src, 0), &op0);
+
+ if (GET_CODE (memexp) == LABEL_REF)
+ return 8;
+ if (CSKY_VREG_P (dstreg))
+ return 4;
+ return 8;
+ }
+ else if (GET_CODE (src) == CONST_INT || GET_CODE (src) == CONST_DOUBLE)
+ {
+ split_double (src, operands + 2, operands + 3);
+ if (CSKY_CONST_OK_FOR_N (INTVAL (operands[2]) + 1)
+ && CSKY_CONST_OK_FOR_N (INTVAL (operands[3]) + 1)
+ && REGNO (operands[0]) < 6)
+ return 4;
+ else
+ return 8;
+ }
+ }
+ else if (GET_CODE (dst) == MEM && GET_CODE (src) == REG)
+ {
+ rtx memexp = XEXP (dst, 0);
+ int srcreg = REGNO (src);
+ int offset = -1;
+ if (CSKY_VREG_P (srcreg))
+ return 4;
+
+ if (GET_CODE (memexp) == REG)
+ offset = 0;
+ else if (GET_CODE (memexp) == PLUS)
+ {
+ if (GET_CODE (XEXP (memexp, 0)) == REG)
+ offset = INTVAL (XEXP (memexp, 1));
+ else if (GET_CODE (XEXP (memexp, 1)) == REG)
+ offset = INTVAL (XEXP (memexp, 0));
+ else
+ gcc_unreachable ();
+ }
+ else
+ gcc_unreachable ();
+
+ if (srcreg <= 6 && offset <= 1020)
+ return 4;
+ else if ((srcreg == 7 && offset <= 1024) || (srcreg <= 7 && offset == 1024))
+ return 6;
+ else
+ return 8;
+ }
+ else
+ gcc_unreachable ();
+
+ return 0;
+}
+
+/* Output float point load/store instructions for fpuv3. */
+
+const char *
+fpuv3_output_move (rtx *operands)
+{
+ rtx reg, mem, addr, ops[2];
+ bool isload = REG_P (operands[0]);
+
+ const char *templ = "f%s%s.%s\t%%0, %%1";
+ char buff[50];
+ machine_mode mode;
+
+ reg = operands[isload ? 0 : 1];
+ mem = operands[isload ? 1 : 0];
+
+ gcc_assert (REG_P (reg));
+ gcc_assert (CSKY_VREG_P (REGNO (reg)));
+ gcc_assert (MEM_P (mem));
+
+ mode = GET_MODE (reg);
+ const char *type = mode == DFmode ? "64" :
+ mode == SFmode ? "32" :
+ mode == HFmode ? "16" :
+ NULL;
+ gcc_assert(type != NULL);
+
+ addr = XEXP (mem, 0);
+ struct csky_address caddr;
+ decompose_csky_address (addr, &caddr);
+
+ ops[0] = reg;
+ ops[1] = mem;
+ sprintf (buff, templ,
+ isload ? "ld" : "st",
+ caddr.index ? "r" : "",
+ type);
+ output_asm_insn (buff, ops);
+
+ return "";
+}
+
+/* Check if a const_double can be used by a VFP fmovi instruction. */
+
+int
+fpuv3_const_double_rtx (rtx x)
+{
+ REAL_VALUE_TYPE r, m;
+ r = *CONST_DOUBLE_REAL_VALUE (x);
+
+ /* Fpuv3 doesn't support the following values. */
+ if (REAL_VALUE_ISINF (r) || REAL_VALUE_ISNAN (r) || REAL_VALUE_MINUS_ZERO (r)
+ || r.cl == rvc_zero)
+ return 0;
+
+ /* Extract sign, exponent and mantissa. */
+ int exponent;
+ r = real_value_abs (&r);
+ exponent = REAL_EXP (&r);
+
+ bool fail;
+ unsigned HOST_WIDE_INT mantissa, mant_hi;
+ unsigned HOST_WIDE_INT mask;
+ int point_pos = 2 * HOST_BITS_PER_WIDE_INT - 1;
+ real_ldexp (&m, &r, point_pos - exponent);
+ wide_int w = real_to_integer (&m, &fail, HOST_BITS_PER_WIDE_INT * 2);
+ mantissa = w.elt (0);
+ mant_hi = w.elt (1);
+
+ exponent -= 1;
+
+ if (!IN_RANGE (exponent, -4, 11))
+ return 0;
+
+ /* If there are bits set in the low part of the mantissa, these values are
+ not supported. */
+ if (mantissa != 0)
+ return 0;
+
+ /* Now, make the mantissa contain the most-significant bits, and the
+ point_pos indicates the number of these bits. */
+ point_pos -= HOST_BITS_PER_WIDE_INT;
+ mantissa = mant_hi;
+
+ /* We can only allow a mantissa of 9 significant digits, top of which is always 1. */
+ mask = ((unsigned HOST_WIDE_INT)1 << (point_pos - 9)) - 1;
+ if ((mantissa & mask) != 0)
+ return 0;
+
+ return 1;
+}
+
+
/* Split operands for an AND expression when OPERANDS[2] is a constant.
Note operands[0] is marked earlyclobber in this case and can be
overwritten. Return true if "DONE", false otherwise. */
+
bool
csky_split_and (rtx *operands)
{
@@ -4650,6 +5052,7 @@ csky_split_and (rtx *operands)
/* Split operands for an IOR expression when OPERANDS[2] is a constant.
Note operands[0] is marked earlyclobber in this case and can be
overwritten. Return true if "DONE", false otherwise. */
+
bool
csky_split_ior (rtx *operands)
{
@@ -4717,6 +5120,7 @@ csky_split_ior (rtx *operands)
/* Split operands for an XOR expression when OPERANDS[2] is a constant.
Note operands[0] is marked earlyclobber in this case and can be
overwritten. Return true if "DONE", false otherwise. */
+
bool
csky_split_xor (rtx *operands)
{
@@ -4765,6 +5169,7 @@ csky_split_xor (rtx *operands)
/* Return true if X is an address form involving a symbol or label ref. */
+
bool
csky_symbolic_address_p (rtx x)
{
@@ -4793,6 +5198,9 @@ csky_emit_compare (enum rtx_code code, rtx op0, rtx op1)
bool invert;
rtx cc_reg = gen_rtx_REG (CCmode, CSKY_CC_REGNUM);
+ if (GET_MODE_CLASS(GET_MODE (op0)) == MODE_FLOAT)
+ return csky_emit_compare_float(code, op0, op1);
+
if (GET_CODE (op1) == CONST_INT)
{
HOST_WIDE_INT val = INTVAL (op1);
@@ -5707,6 +6115,7 @@ tls_unspec_mentioned_p (rtx x)
/* Implement LEGITIMATE_PIC_OPERAND_P. */
+
bool
csky_legitimate_pic_operand_p (rtx x)
{
@@ -5938,33 +6347,20 @@ csky_emit_compare_float (enum rtx_code code, rtx op0, rtx op1)
op1 = force_reg (mode, op1);
invert = false;
+
switch (code)
{
case EQ:
code = NE;
invert = true;
break;
-
- case NE:
- break;
- case LE:
- if (op1 == CONST0_RTX (mode))
- op1 = force_reg (mode, op1);
- break;
case GT:
- if (op1 == CONST0_RTX (mode))
- op1 = force_reg (mode, op1);
- break;
- case GE:
- break;
case LT:
- if (op1 == CONST0_RTX (mode))
- {
- code = GE;
- invert = true;
- }
- break;
- case UNORDERED:
+ case LE:
+ if (op1 == CONST0_RTX (mode) && (CSKY_ISA_FEATURE_GET(fpv2_sf)
+ || CSKY_ISA_FEATURE_GET(fpv2_df)
+ || CSKY_ISA_FEATURE_GET(fpv2_divd)))
+ op1 = force_reg (mode, op1);
break;
case ORDERED:
code = UNORDERED;
@@ -5980,10 +6376,11 @@ csky_emit_compare_float (enum rtx_code code, rtx op0, rtx op1)
return invert;
}
-/* Support for the Q memory constraint. Returns true if OP is a MEM RTX
- with an address consisting of base + index or base + displacement. */
+/* Support for the Q or W memory constraint. Returns true if OP is a MEM
+ RTX with an address consisting of base + index or base + displacement. */
+
bool
-csky_valid_fpuv2_mem_operand (rtx op)
+csky_valid_mem_constraint_operand (rtx op, const char *constraint)
{
struct csky_address addr;
@@ -5998,7 +6395,7 @@ csky_valid_fpuv2_mem_operand (rtx op)
return false;
/* Verify index operand. */
- if (addr.index)
+ if (addr.index && (constraint[0] == 'Q' || constraint[0] == 'W'))
{
if (!is_csky_address_register_rtx_p (addr.index, 0))
return false;
@@ -6010,7 +6407,7 @@ csky_valid_fpuv2_mem_operand (rtx op)
return false;
}
/* Verify disp operand. */
- else if (addr.disp)
+ else if (addr.disp && constraint[0] == 'Q')
{
rtx disp = addr.disp;
@@ -6023,7 +6420,11 @@ csky_valid_fpuv2_mem_operand (rtx op)
return false;
}
- return true;
+ else if (constraint[0] == 'Q')
+ /* Single reg is valid for 'Q'. */
+ return true;
+
+ return false;
}
@@ -6442,7 +6843,7 @@ ck803_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
}
}
-/* TARGET_RTX_COSTS helper for ck807+ arches. */
+/* TARGET_RTX_COSTS helper for ck807/ck810 arches. */
static bool
ck807_ck810_rtx_costs (rtx x, int code,
@@ -6473,6 +6874,52 @@ ck807_ck810_rtx_costs (rtx x, int code,
}
}
+/* TARGET_RTX_COSTS helper for ck860 arches. */
+
+static bool
+ck860_rtx_costs (rtx x, int code, machine_mode mode,
+ int outer_code ATTRIBUTE_UNUSED,
+ int *total, bool speed ATTRIBUTE_UNUSED)
+{
+ switch (code)
+ {
+ case PLUS:
+ /* The costs of mula is 1 more than mult. */
+ if (GET_CODE (XEXP (x, 0)) == MULT && REG_P (XEXP (x, 1)) && speed)
+ {
+ rtx mul_op0 = XEXP (XEXP (x, 0), 0);
+ rtx mul_op1 = XEXP (XEXP (x, 0), 1);
+ if (REG_P (mul_op0) && REG_P (mul_op1))
+ {
+ *total = COSTS_N_INSNS (1);
+ *total += rtx_cost (XEXP (x, 0), mode,
+ (enum rtx_code) code, 0, speed);
+ return true;
+ }
+ }
+ return false;
+ case MULT:
+ if (REG_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1)))
+ {
+ HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
+ if (val % 2 == 0 && val < 0xffffffff && val > 0)
+ {
+ *total = COSTS_N_INSNS (1);
+ return true;
+ }
+ }
+ return false;
+
+ case CONST:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ *total = COSTS_N_INSNS (3);
+ return true;
+ default:
+ return false;
+ }
+}
+
/* Implement TARGET_RTX_COSTS, to compute a (partial) cost for rtx X.
Return true if the complete cost has been computed, and false if
@@ -6491,6 +6938,8 @@ csky_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED, int outer_code,
return ck803_rtx_costs (x, code, outer_code, total, speed);
else if (CSKY_TARGET_ARCH (CK807) || CSKY_TARGET_ARCH (CK810))
return ck807_ck810_rtx_costs (x, code, outer_code, total, speed);
+ else if (CSKY_TARGET_ARCH (CK860))
+ return ck860_rtx_costs (x, code, mode, outer_code, total, speed);
else
gcc_unreachable ();
}
@@ -6633,6 +7082,7 @@ csky_warn_func_return (tree decl)
/* Implement TARGET_RETURN_IN_MEMORY to decide whether TYPE should be
returned in memory (true) or in a register (false).
FNTYPE is the type of the function making the call. */
+
static bool
csky_return_in_memory (const_tree type,
const_tree fntype ATTRIBUTE_UNUSED)
@@ -6646,6 +7096,7 @@ csky_return_in_memory (const_tree type,
Dwarf models VFP registers as 64-bit or 128-bit registers default.
GCC models tham as 32-bit registers, so we need to describe this to
the DWARF generation code. Other registers can use the default. */
+
static rtx
csky_dwarf_register_span (rtx rtl)
{
@@ -6659,11 +7110,15 @@ csky_dwarf_register_span (rtx rtl)
if (!CSKY_VREG_P (regno))
return NULL_RTX;
+ if (CSKY_VREG_HI_P (regno))
+ regno += 16;
+
mode = GET_MODE (rtl);
if (GET_MODE_SIZE (mode) < 8)
return NULL_RTX;
- if (TARGET_SOFT_FPU)
+
+ if (TARGET_SINGLE_FPU)
{
nregs = GET_MODE_SIZE (mode) / 4;
for (i = 0; i < nregs; i += 2)
@@ -6684,9 +7139,18 @@ csky_dwarf_register_span (rtx rtl)
as the CPU bit width. Transform the 64-bit FPU registers to
32 bits here, and we will modify the unwind processing to
fit CSKY architecture later. */
- nregs = GET_MODE_SIZE (mode) / 8;
- for (i = 0; i < nregs; i++)
- parts[i] = gen_rtx_REG (SImode, regno + i);
+ nregs = GET_MODE_SIZE (mode) / 4;
+ for (i = 0; i < nregs; i += 2)
+ if (TARGET_BIG_ENDIAN)
+ {
+ parts[i] = gen_rtx_REG (SImode, regno + i - 16);
+ parts[i + 1] = gen_rtx_REG (SImode, regno + i);
+ }
+ else
+ {
+ parts[i] = gen_rtx_REG (SImode, regno + i);
+ parts[i + 1] = gen_rtx_REG (SImode, regno + i - 16);
+ }
}
return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nregs , parts));
@@ -6847,6 +7311,34 @@ csky_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
pcum->is_stdarg = true;
}
+
+/* Implement the TARGET_INIT_BUILTINS target macro. */
+
+void
+csky_init_builtins (void)
+{
+ /* Inint fp16. */
+ static tree csky_floatHF_type_node = make_node (REAL_TYPE);
+ TYPE_PRECISION (csky_floatHF_type_node) = GET_MODE_PRECISION (HFmode);
+ layout_type (csky_floatHF_type_node);
+ (*lang_hooks.types.register_builtin_type) (csky_floatHF_type_node, "__fp16");
+}
+
+
+/* Implement TARGET_MANGLE_TYPE. */
+
+static const char *
+csky_mangle_type (const_tree type)
+{
+ if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+ && DECL_NAME (TYPE_NAME (type))
+ && !strcmp (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))), "__fp16"))
+ return "__fp16";
+
+ /* Use the default mangling. */
+ return NULL;
+}
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-csky.h"