aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/sh/sh.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/sh/sh.c')
-rw-r--r--gcc/config/sh/sh.c136
1 files changed, 133 insertions, 3 deletions
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index 4207719dc44..0015f7029a4 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -48,6 +48,7 @@ Boston, MA 02111-1307, USA. */
#include "basic-block.h"
#include "ra.h"
#include "cfglayout.h"
+#include "intl.h"
int code_for_indirect_jump_scratch = CODE_FOR_indirect_jump_scratch;
@@ -246,6 +247,7 @@ static rtx sh_builtin_saveregs (void);
static void sh_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, tree, int *, int);
static bool sh_strict_argument_naming (CUMULATIVE_ARGS *);
static bool sh_pretend_outgoing_varargs_named (CUMULATIVE_ARGS *);
+static tree sh_build_builtin_va_list (void);
/* Initialize the GCC target structure. */
@@ -345,6 +347,12 @@ static bool sh_pretend_outgoing_varargs_named (CUMULATIVE_ARGS *);
#undef TARGET_PRETEND_OUTGOING_VARARGS_NAMED
#define TARGET_PRETEND_OUTGOING_VARARGS_NAMED sh_pretend_outgoing_varargs_named
+#undef TARGET_BUILD_BUILTIN_VA_LIST
+#define TARGET_BUILD_BUILTIN_VA_LIST sh_build_builtin_va_list
+
+#undef TARGET_PCH_VALID_P
+#define TARGET_PCH_VALID_P sh_pch_valid_p
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Print the operand address in x to the stream. */
@@ -5911,8 +5919,8 @@ sh_builtin_saveregs (void)
/* Define the `__builtin_va_list' type for the ABI. */
-tree
-sh_build_va_list (void)
+static tree
+sh_build_builtin_va_list (void)
{
tree f_next_o, f_next_o_limit, f_next_fp, f_next_fp_limit, f_next_stack;
tree record;
@@ -5921,7 +5929,7 @@ sh_build_va_list (void)
|| TARGET_HITACHI || sh_cfun_attr_renesas_p ())
return ptr_type_node;
- record = make_node (RECORD_TYPE);
+ record = (*lang_hooks.types.make_type) (RECORD_TYPE);
f_next_o = build_decl (FIELD_DECL, get_identifier ("__va_next_o"),
ptr_type_node);
@@ -6833,6 +6841,90 @@ sh_cfun_interrupt_handler_p (void)
DECL_ATTRIBUTES (current_function_decl))
!= NULL_TREE);
}
+
+/* ??? target_switches in toplev.c is static, hence we have to duplicate it. */
+static const struct
+{
+ const char *const name;
+ const int value;
+ const char *const description;
+}
+sh_target_switches[] = TARGET_SWITCHES;
+#define target_switches sh_target_switches
+
+/* Like default_pch_valid_p, but take flag_mask into account. */
+const char *
+sh_pch_valid_p (const void *data_p, size_t len)
+{
+ const char *data = (const char *)data_p;
+ const char *flag_that_differs = NULL;
+ size_t i;
+ int old_flags;
+ int flag_mask
+ = (SH1_BIT | SH2_BIT | SH3_BIT | SH_E_BIT | HARD_SH4_BIT | FPU_SINGLE_BIT
+ | SH4_BIT | HITACHI_BIT | LITTLE_ENDIAN_BIT);
+
+ /* -fpic and -fpie also usually make a PCH invalid. */
+ if (data[0] != flag_pic)
+ return _("created and used with different settings of -fpic");
+ if (data[1] != flag_pie)
+ return _("created and used with different settings of -fpie");
+ data += 2;
+
+ /* Check target_flags. */
+ memcpy (&old_flags, data, sizeof (target_flags));
+ if (((old_flags ^ target_flags) & flag_mask) != 0)
+ {
+ for (i = 0; i < ARRAY_SIZE (target_switches); i++)
+ {
+ int bits;
+
+ bits = target_switches[i].value;
+ if (bits < 0)
+ bits = -bits;
+ bits &= flag_mask;
+ if ((target_flags & bits) != (old_flags & bits))
+ {
+ flag_that_differs = target_switches[i].name;
+ goto make_message;
+ }
+ }
+ abort ();
+ }
+ data += sizeof (target_flags);
+ len -= sizeof (target_flags);
+
+ /* Check string options. */
+#ifdef TARGET_OPTIONS
+ for (i = 0; i < ARRAY_SIZE (target_options); i++)
+ {
+ const char *str = *target_options[i].variable;
+ size_t l;
+ if (! str)
+ str = "";
+ l = strlen (str) + 1;
+ if (len < l || memcmp (data, str, l) != 0)
+ {
+ flag_that_differs = target_options[i].prefix;
+ goto make_message;
+ }
+ data += l;
+ len -= l;
+ }
+#endif
+
+ return NULL;
+
+ make_message:
+ {
+ char *r;
+ asprintf (&r, _("created and used with differing settings of `-m%s'"),
+ flag_that_differs);
+ if (r == NULL)
+ return _("out of memory");
+ return r;
+ }
+}
/* Predicates used by the templates. */
@@ -8806,6 +8898,15 @@ sh_register_operand (rtx op, enum machine_mode mode)
return register_operand (op, mode);
}
+int
+cmpsi_operand (rtx op, enum machine_mode mode)
+{
+ if (GET_CODE (op) == REG && REGNO (op) == T_REG
+ && GET_MODE (op) == SImode)
+ return 1;
+ return arith_operand (op, mode);
+}
+
static rtx emit_load_ptr (rtx, rtx);
static rtx
@@ -9037,4 +9138,33 @@ sh_get_pr_initial_val (void)
return val;
}
+int
+sh_expand_t_scc (enum rtx_code code, rtx target)
+{
+ rtx result = target;
+ HOST_WIDE_INT val;
+
+ if (GET_CODE (sh_compare_op0) != REG || REGNO (sh_compare_op0) != T_REG
+ || GET_CODE (sh_compare_op1) != CONST_INT)
+ return 0;
+ if (GET_CODE (result) != REG)
+ result = gen_reg_rtx (SImode);
+ val = INTVAL (sh_compare_op1);
+ if ((code == EQ && val == 1) || (code == NE && val == 0))
+ emit_insn (gen_movt (result));
+ else if ((code == EQ && val == 0) || (code == NE && val == 1))
+ {
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, result));
+ emit_insn (gen_subc (result, result, result));
+ emit_insn (gen_addsi3 (result, result, GEN_INT (1)));
+ }
+ else if (code == EQ || code == NE)
+ emit_insn (gen_move_insn (result, GEN_INT (code == NE)));
+ else
+ return 0;
+ if (result != target)
+ emit_move_insn (target, result);
+ return 1;
+}
+
#include "gt-sh.h"