-/* Copyright (C) 2006-2017 Free Software Foundation, Inc.
+/* Copyright (C) 2006-2019 Free Software Foundation, Inc.
This file is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
+#define IN_TARGET_CODE 1
+
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "dumpfile.h"
#include "builtins.h"
#include "rtl-iter.h"
+#include "flags.h"
+#include "toplev.h"
/* This file should be included last. */
#include "target-def.h"
flag_omit_frame_pointer = 1;
/* Functions must be 8 byte aligned so we correctly handle dual issue */
- if (align_functions < 8)
- align_functions = 8;
+ parse_alignment_opts ();
+ if (align_functions.levels[0].get_value () < 8)
+ str_align_functions = "8";
spu_hint_dist = 8*4 - spu_max_nops*4;
if (spu_hint_dist < 0)
else if (strcmp (&spu_arch_string[0], "celledp") == 0)
spu_arch = PROCESSOR_CELLEDP;
else
- error ("bad value (%s) for -march= switch", spu_arch_string);
+ error ("bad value (%s) for %<-march=%> switch", spu_arch_string);
}
/* Determine processor to tune for. */
else if (strcmp (&spu_tune_string[0], "celledp") == 0)
spu_tune = PROCESSOR_CELLEDP;
else
- error ("bad value (%s) for -mtune= switch", spu_tune_string);
+ error ("bad value (%s) for %<-mtune=%> switch", spu_tune_string);
}
/* Change defaults according to the processor architecture. */
REAL_MODE_FORMAT (SFmode) = &spu_single_format;
}
\f
+/* Implement TARGET_HARD_REGNO_NREGS. */
+
+static unsigned int
+spu_hard_regno_nregs (unsigned int, machine_mode mode)
+{
+ return CEIL (GET_MODE_BITSIZE (mode), MAX_FIXED_MODE_SIZE);
+}
+
/* Handle an attribute requiring a FUNCTION_DECL; arguments as in
struct attribute_spec.handler. */
op_size = 32;
}
/* If it is not a MODE_INT (and/or it is smaller than SI) add a SUBREG. */
- mode = mode_for_size (op_size, MODE_INT, 0);
+ mode = int_mode_for_size (op_size, 0).require ();
if (mode != GET_MODE (op))
op = gen_rtx_SUBREG (mode, op, 0);
return op;
rtx target = operands[0];
int compare_size = GET_MODE_BITSIZE (comp_mode);
int target_size = GET_MODE_BITSIZE (GET_MODE (target));
- machine_mode mode = mode_for_size (target_size, MODE_INT, 0);
+ machine_mode mode = int_mode_for_size (target_size, 0).require ();
rtx select_mask;
rtx op_t = operands[2];
rtx op_f = operands[3];
if (total_size > 0)
{
- if (flag_stack_check)
+ if (flag_stack_check || flag_stack_clash_protection)
{
/* We compare against total_size-1 because
($sp >= total_size) <=> ($sp > total_size-1) */
spu_const (machine_mode mode, HOST_WIDE_INT val)
{
rtx inner;
- rtvec v;
- int units, i;
gcc_assert (GET_MODE_CLASS (mode) == MODE_INT
|| GET_MODE_CLASS (mode) == MODE_FLOAT
else
inner = hwint_to_const_double (GET_MODE_INNER (mode), val);
- units = GET_MODE_NUNITS (mode);
-
- v = rtvec_alloc (units);
-
- for (i = 0; i < units; ++i)
- RTVEC_ELT (v, i) = inner;
-
- return gen_rtx_CONST_VECTOR (mode, v);
+ return gen_const_vec_duplicate (mode, inner);
}
/* Create a MODE vector constant from 4 ints. */
for (; insn; insn = next_insn)
{
next_insn = next_active_insn (insn);
- if (INSN_CODE (insn) == CODE_FOR_iprefetch
- || INSN_CODE (insn) == CODE_FOR_hbr)
+ if (INSN_P (insn)
+ && (INSN_CODE (insn) == CODE_FOR_iprefetch
+ || INSN_CODE (insn) == CODE_FOR_hbr))
{
if (hbr_insn)
{
}
hbr_insn = insn;
}
- if (INSN_CODE (insn) == CODE_FOR_blockage && next_insn)
+ if (INSN_P (insn) && INSN_CODE (insn) == CODE_FOR_blockage && next_insn)
{
if (GET_MODE (insn) == TImode)
PUT_MODE (next_insn, TImode);
spu_sched_init (FILE *file ATTRIBUTE_UNUSED, int verbose ATTRIBUTE_UNUSED,
int max_ready ATTRIBUTE_UNUSED)
{
- if (align_labels > 4 || align_loops > 4 || align_jumps > 4)
+ if (align_labels.levels[0].get_value () > 4
+ || align_loops.levels[0].get_value () > 4
+ || align_jumps.levels[0].get_value () > 4)
{
/* When any block might be at least 8-byte aligned, assume they
will all be at least 8-byte aligned to make sure dual issue
jump_insn. We adjust here so higher cost insns will get scheduled
earlier. */
if (JUMP_P (insn) && dep_type == REG_DEP_ANTI)
- return insn_cost (dep_insn) - 3;
+ return insn_sched_cost (dep_insn) - 3;
return cost;
}
constant_to_array (mode, op, arr);
bytes = GET_MODE_UNIT_SIZE (mode);
- mode = mode_for_size (GET_MODE_UNIT_BITSIZE (mode), MODE_INT, 0);
+ mode = int_mode_for_mode (GET_MODE_INNER (mode)).require ();
/* Check that bytes are repeated. */
for (i = bytes; i < 16; i += bytes)
mode = GET_MODE_INNER (mode);
bytes = GET_MODE_SIZE (mode);
- int_mode = mode_for_size (GET_MODE_BITSIZE (mode), MODE_INT, 0);
+ int_mode = int_mode_for_mode (mode).require ();
/* Check that bytes are repeated. */
for (i = bytes; i < 16; i += bytes)
? ((int_size_in_bytes (type) + 15) / 16)
: mode == VOIDmode
? 1
- : HARD_REGNO_NREGS (cum, mode));
+ : spu_hard_regno_nregs (FIRST_ARG_REGNUM, mode));
+}
+
+/* Implement TARGET_FUNCTION_ARG_OFFSET. The SPU ABI wants 32/64-bit
+ types at offset 0 in the quad-word on the stack. 8/16-bit types
+ should be at offsets 3/2 respectively. */
+
+static HOST_WIDE_INT
+spu_function_arg_offset (machine_mode mode, const_tree type)
+{
+ if (type && INTEGRAL_TYPE_P (type) && GET_MODE_SIZE (mode) < 4)
+ return 4 - GET_MODE_SIZE (mode);
+ return 0;
+}
+
+/* Implement TARGET_FUNCTION_ARG_PADDING. */
+
+static pad_direction
+spu_function_arg_padding (machine_mode, const_tree)
+{
+ return PAD_UPWARD;
}
/* Variable sized types are passed by reference. */
which is both 16-byte aligned and padded to a 16-byte boundary. This
would make it safe to store with a single instruction.
We guarantee the alignment and padding for static objects by aligning
- all of them to 16-bytes. (DATA_ALIGNMENT and CONSTANT_ALIGNMENT.)
+ all of them to 16-bytes. (DATA_ALIGNMENT and TARGET_CONSTANT_ALIGNMENT.)
FIXME: We currently cannot guarantee this for objects on the stack
because assign_parm_setup_stack calls assign_stack_local with the
alignment of the parameter mode and in that case the alignment never
spu_convert_move (rtx dst, rtx src)
{
machine_mode mode = GET_MODE (dst);
- machine_mode int_mode = mode_for_size (GET_MODE_BITSIZE (mode), MODE_INT, 0);
+ machine_mode int_mode = int_mode_for_mode (mode).require ();
rtx reg;
gcc_assert (GET_MODE (src) == TImode);
reg = int_mode != mode ? gen_reg_rtx (int_mode) : dst;
dash = strchr (str, '-');
if (!dash)
{
- warning (0, "value of -mfixed-range must have form REG1-REG2");
+ warning (0, "value of %<-mfixed-range%> must have form REG1-REG2");
return;
}
*dash = '\0';
emit_insn (gen_spu_convert (sp, stack_pointer_rtx));
emit_insn (gen_subv4si3 (sp, sp, splatted));
- if (flag_stack_check)
+ if (flag_stack_check || flag_stack_clash_protection)
{
rtx avail = gen_reg_rtx(SImode);
rtx result = gen_reg_rtx(SImode);
return 2;
case unaligned_load:
+ case vector_gather_load:
+ case vector_scatter_store:
return 2;
case cond_branch_taken:
return (GET_MODE_BITSIZE (mode1) <= MAX_FIXED_MODE_SIZE
&& GET_MODE_BITSIZE (mode2) <= MAX_FIXED_MODE_SIZE);
}
+
+/* Implement TARGET_CAN_CHANGE_MODE_CLASS. GCC assumes that modes are
+ in the lowpart of a register, which is only true for SPU. */
+
+static bool
+spu_can_change_mode_class (machine_mode from, machine_mode to, reg_class_t)
+{
+ return (GET_MODE_SIZE (from) == GET_MODE_SIZE (to)
+ || (GET_MODE_SIZE (from) <= 4 && GET_MODE_SIZE (to) <= 4)
+ || (GET_MODE_SIZE (from) >= 16 && GET_MODE_SIZE (to) >= 16));
+}
+
+/* Implement TARGET_TRULY_NOOP_TRUNCATION. */
+
+static bool
+spu_truly_noop_truncation (poly_uint64 outprec, poly_uint64 inprec)
+{
+ return inprec <= 32 && outprec <= inprec;
+}
+
+/* Implement TARGET_STATIC_RTX_ALIGNMENT.
+
+ Make all static objects 16-byte aligned. This allows us to assume
+ they are also padded to 16 bytes, which means we can use a single
+ load or store instruction to access them. */
+
+static HOST_WIDE_INT
+spu_static_rtx_alignment (machine_mode mode)
+{
+ return MAX (GET_MODE_ALIGNMENT (mode), 128);
+}
+
+/* Implement TARGET_CONSTANT_ALIGNMENT.
+
+ Make all static objects 16-byte aligned. This allows us to assume
+ they are also padded to 16 bytes, which means we can use a single
+ load or store instruction to access them. */
+
+static HOST_WIDE_INT
+spu_constant_alignment (const_tree, HOST_WIDE_INT align)
+{
+ return MAX (align, 128);
+}
\f
/* Table of machine attributes. */
static const struct attribute_spec spu_attribute_table[] =
{
- /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
- { "naked", 0, 0, true, false, false, spu_handle_fndecl_attribute,
- false },
- { "spu_vector", 0, 0, false, true, false, spu_handle_vector_attribute,
- false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
+ affects_type_identity, handler, exclude } */
+ { "naked", 0, 0, true, false, false, false,
+ spu_handle_fndecl_attribute, NULL },
+ { "spu_vector", 0, 0, false, true, false, false,
+ spu_handle_vector_attribute, NULL },
+ { NULL, 0, 0, false, false, false, false, NULL, NULL }
};
/* TARGET overrides. */
#undef TARGET_FUNCTION_ARG_ADVANCE
#define TARGET_FUNCTION_ARG_ADVANCE spu_function_arg_advance
+#undef TARGET_FUNCTION_ARG_OFFSET
+#define TARGET_FUNCTION_ARG_OFFSET spu_function_arg_offset
+
+#undef TARGET_FUNCTION_ARG_PADDING
+#define TARGET_FUNCTION_ARG_PADDING spu_function_arg_padding
+
#undef TARGET_MUST_PASS_IN_STACK
#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
#undef TARGET_MODES_TIEABLE_P
#define TARGET_MODES_TIEABLE_P spu_modes_tieable_p
+#undef TARGET_HARD_REGNO_NREGS
+#define TARGET_HARD_REGNO_NREGS spu_hard_regno_nregs
+
+#undef TARGET_CAN_CHANGE_MODE_CLASS
+#define TARGET_CAN_CHANGE_MODE_CLASS spu_can_change_mode_class
+
+#undef TARGET_TRULY_NOOP_TRUNCATION
+#define TARGET_TRULY_NOOP_TRUNCATION spu_truly_noop_truncation
+
+#undef TARGET_STATIC_RTX_ALIGNMENT
+#define TARGET_STATIC_RTX_ALIGNMENT spu_static_rtx_alignment
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT spu_constant_alignment
+
+#undef TARGET_HAVE_SPECULATION_SAFE_VALUE
+#define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-spu.h"